web-dev-qa-db-ja.com

<context:annotation-config>と<context:component-scan>の違い

私はSpring 3を学んでいますが、<context:annotation-config><context:component-scan>の背後にある機能を把握していないようです。

私が読んだものからは異なるアノテーション(@Required、@ Autowiredなどvs @ Component、@ Repository、@ Serviceなど)を処理しているように見えますが、私が読んだものからも同じBeanポストプロセッサクラスを登録します。

私をさらに混乱させるために、annotation-config<context:component-scan>属性があります。

誰かがこれらのタグに光を当てることはできますか?似ているもの、違うもの、他のものに取って代わられるもの、お互いを完成させるもの、どちらか一方が必要なのか、両方?

645
user938214097

<context:annotation-config>は、アプリケーションコンテキストにすでに登録されているBeanのアノテーションをアクティブにするために使用されます(XMLで定義されているかパッケージスキャンで定義されているかにかかわらず)。

<context:component-scan><context:annotation-config>が行うこともできますが、<context:component-scan>はパッケージをスキャンしてアプリケーションコンテキスト内でBeanを見つけて登録することもできます。

いくつかの例を使用して、相違点と類似点を示します。

ABCにインジェクトされる、BCAの3つのBeanの基本的な設定から始めましょう。

package com.xxx;
public class B {
  public B() {
    System.out.println("creating bean B: " + this);
  }
}

package com.xxx;
public class C {
  public C() {
    System.out.println("creating bean C: " + this);
  }
}

package com.yyy;
import com.xxx.B;
import com.xxx.C;
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc; 
  }
}

次のXML構成では

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A">
  <property name="bbb" ref="bBean" />
  <property name="ccc" ref="cBean" />
</bean>

コンテキストをロードすると、以下の出力が生成されます。

creating bean B: com.xxx.B@c2ff5
creating bean C: com.xxx.C@1e8a1f6
creating bean A: com.yyy.A@1e152c5
setting A.bbb with com.xxx.B@c2ff5
setting A.ccc with com.xxx.C@1e8a1f6

はい、これは予想される出力です。しかし、これは「古いスタイル」の春です。アノテーションが追加されたので、XMLを単純化するためにそれらを使用しましょう。

まず、Bean bbbcccおよびAプロパティを次のように自動配線します。

package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import com.xxx.B;
import com.xxx.C;
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  @Autowired
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  @Autowired
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc;
  }
}

これにより、XMLから次の行を削除できます。

<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />

私のXMLはこれで単純化されました。

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

コンテキストをロードすると、次のような出力が得られます。

creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf

さて、これは間違っています!何が起こった?なぜ私の財産は自動配線されていないのですか?

アノテーションは素晴らしい機能ですが、それ自体では何もしません。彼らはものに注釈をつけるだけです。注釈を見つけてそれを使って何かをするための処理ツールが必要です。

<context:annotation-config>が助けになります。これは、それ自体が定義されているのと同じアプリケーションコンテキストで定義されているBeanで見つかったアノテーションに対するアクションをアクティブにします。

XMLをこれに変更すると、

<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

アプリケーションコンテキストをロードすると、正しい結果が得られます。

creating bean B: com.xxx.B@15663a2
creating bean C: com.xxx.C@cd5f8b
creating bean A: com.yyy.A@157aa53
setting A.bbb with com.xxx.B@15663a2
setting A.ccc with com.xxx.C@cd5f8b

わかりました、これはいいことですが、XMLから2行削除して1行追加しました。それほど大きな違いはありません。注釈付きの考え方は、XMLを削除することになっているということです。

それでは、XML定義を削除し、それらをすべて注釈に置き換えましょう。

package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class B {
  public B() {
    System.out.println("creating bean B: " + this);
  }
}

package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class C {
  public C() {
    System.out.println("creating bean C: " + this);
  }
}

package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.xxx.B;
import com.xxx.C;
@Component
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  @Autowired
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  @Autowired
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc;
  }
}

XMLでは、これだけを守ります。

<context:annotation-config />

コンテキストをロードすると結果は...何もしません。 Beanは作成されず、Beanも自動配線されません。何もない!

これは、最初の段落で述べたように、<context:annotation-config />はアプリケーションコンテキスト内で登録されたBeanに対してのみ機能するためです。 3つのBeanのXML構成を削除したので、Beanは作成されず、<context:annotation-config />には作業対象となる「ターゲット」がありません。

しかし、<context:component-scan>がパッケージをスキャンして「ターゲット」を処理できるのであれば、問題にはなりません。 XML設定の内容を次のエントリに変更しましょう。

<context:component-scan base-package="com.xxx" />

コンテキストをロードすると、次のような出力が得られます。

creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff

うーん...何かが足りない。どうして?

クラスを詳しく見てみると、クラスAにはパッケージcom.yyyがありますが、<context:component-scan>を使用するようにcom.xxxで指定したので、これは私のAクラスを完全に見逃し、com.xxxパッケージにあるBおよびCのみを拾いました。

これを修正するために、私はこの他のパッケージも追加します。

<context:component-scan base-package="com.xxx,com.yyy" />

そして今、期待通りの結果が得られます。

creating bean B: com.xxx.B@cd5f8b
creating bean C: com.xxx.C@15ac3c9
creating bean A: com.yyy.A@ec4a87
setting A.bbb with com.xxx.B@cd5f8b
setting A.ccc with com.xxx.C@15ac3c9

以上です!これでXML定義がなくなり、注釈が付きます。

最後の例として、アノテーション付きクラスAB、およびCを維持し、次のものをXMLに追加すると、コンテキストをロードした後に何が得られますか。

<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

それでも正しい結果が得られます。

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

クラスAのBeanがスキャンによって取得されない場合でも、処理ツールは、XMLに手動で登録されたAの場合でも、アプリケーションコンテキストに登録されているすべてのBeanに<context:component-scan>によって適用されます。

しかし、次のXMLがあるとしたら、<context:annotation-config /><context:component-scan>の両方を指定したために、Beanが重複してしまうのでしょうか。

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

いいえ、重複はありません。予想される結果が得られます。

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

これは、両方のタグが同じ処理ツールを登録しているため(<context:annotation-config />が指定されている場合は<context:component-scan>は省略可能)ですが、Springはそれらを1回しか実行しません。

処理ツールを複数回自分で登録したとしても、Springはそれらの魔法を1回しか実行しないようにします。このXML

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
<bean id="bla" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

それでも次のような結果になります。

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@25d2b2
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

さて、それはそれをラップします。

<context:annotation-config><context:component-scan>がどのように機能するのかを理解するために、@ Tomasz Nurkiewiczと@Sean Patrick Floydからの回答とともに、この情報がすべて揃っていることを願います。

1353
user159088

私はこのNiceを見つけました 要約 どの注釈がどの宣言によって拾われるのか。勉強すると、<context:component-scan/><context:annotation-config/>によって認識されるアノテーションのスーパーセットを認識することがわかります。

  • @Component@Service@Repository@Controller@Endpoint
  • @Configuration@Bean@Lazy@Scope@Order@Primary@Profile@DependsOn@Import@ImportResource

ご覧のとおり、<context:component-scan/>は論理的に extends <context:annotation-config/>は、CLASSPATHコンポーネントのスキャン機能とJavaの@Configuration機能を備えています。

160

Springでは2つのことができます。

  1. 豆の自動配線
  2. 豆の自動発見

1.自動配線
通常 applicationContext.xml でBeanを定義し、他のBeanはコンストラクタまたはセッターメソッドを使用して接続されます。 XMLまたはアノテーションを使用してBeanを配線できます。注釈を使用する場合は、注釈をアクティブにする必要があります。また、 applicationContext.xml <context:annotation-config />を追加する必要があります。手動でBean(コンストラクターまたはセッター)を配線する必要がないため、これによって applicationContext.xml のタグの構造が単純化されます。あなたは@Autowireアノテーションを使うことができます、そして、豆はタイプによって配線されます。

手動のXML構成を回避するための一歩前進

2.自動検出
自動検出機能は、 applicationContext.xml <bean>タグを追加する必要すらないという意味で、XMLをさらに一歩単純化したものです。以下のアノテーションの1つで特定のBeanをマークするだけで、Springは自動的にマークされたBeanとそれらの依存関係をSpringコンテナに配線します。注釈は次のとおりです。 @Controller @Service @Component @リポジトリ <context:component-scan>を使用してベースパッケージを指定することで、SpringはコンポーネントをSpringコンテナに自動検出して配線します。


結論として:

  • @Autowired 注釈を使用できるようにするために<context:annotation-config />が使用されています
  • <context:component-scan />は、特定のBeanの検索と自動配線の試行を決定するために使用されます。
89
user2673474

<context:annotation-config>は、XMLで定義されているかコンポーネントスキャンで定義されているかにかかわらず、Bean内のさまざまな注釈をアクティブ化します。

<context:component-scan>はXMLを使わずにbeanを定義するためのものです

詳細については、読んでください。

32

両者の違いは本当に簡単です。

<context:annotation-config /> 

プロパティとBeanのコンストラクタだけを結び付けるように制限された注釈を使用できるようにします。

どこで

<context:component-scan base-package="org.package"/> 

.. _ <context:annotation-config />、_ @Component、_ @Serviceなどのステレオタイプを使用して、_ @Repositoryでできることすべてを有効にします。つまり、コンストラクタやプロパティだけでなく、Bean全体をワイヤリングできます。

28
Sparticles

<context:annotation-config>spring config xmlに既に登録されているbeanのアノテーションをスキャンして有効にします。

<context:component-scan>Bean登録+ <context:annotation-config>


@Autowiredおよび@Required ターゲットプロパティレベルなので、これらのアノテーションを使用する前に、beanをspring IOCに登録する必要があります。これらの注釈を有効にするには、それぞれのBeanを登録するか、<context:annotation-config />を含める必要があります。つまり、<context:annotation-config />は登録されたbeanでのみ動作します。

@Required RequiredAnnotationBeanPostProcessor処理ツールを有効にする
@Autowired AutowiredAnnotationBeanPostProcessor処理ツールを有効にします

注: 注釈自体は何もしません。コアプロセスを担当する 処理ツール が必要です。


@Repository、@Service、および@Controllerは@Componentであり、それらはターゲットクラスレベルです。

<context:component-scan>これはパッケージをスキャンし、Beanを見つけて登録します。また、<context:annotation-config />による作業も含まれます。

アノテーションへのXMLの移行

26
Premraj

<context:annotation-config>タグは、@ Autowiredアノテーションを含むクラスの依存関係の要件を自動的に解決するためにコードベースをスキャンするようにSpringに指示します。

Spring 2.5では、@Resource、@PostConstruct、@ PreDestroyなどのJSR-250注釈のサポートも追加されています。これらの注釈を使用するには、特定のBeanPostProcessorをSpringコンテナ内に登録する必要もあります。いつものように、これらは個別のBean定義として登録できますが、春の設定に<context:annotation-config>タグを含めることで暗黙的に登録することもできます。

アノテーションベースの設定 のSpringドキュメントから引用


Springは、「ステレオタイプ」クラスを自動的に検出し、対応するBean定義をApplicationContextに登録する機能を提供します。

org.springframework.stereotype のjavadocによると:

ステレオタイプとは、アーキテクチャー全体での型またはメソッドの役割(実装レベルではなく概念レベル)を表す注釈です。例:@Controller @Service @Repositoryなど。これらはツールやアスペクトによる使用を目的としています(ポイントカットの理想的なターゲットとなる)。

そのような「ステレオタイプ」クラスを自動検出するには、<context:component-scan>タグが必要です。

<context:component-scan>タグは、指定されたパッケージ(およびそのすべてのサブパッケージ)の下にある注入可能なBeanのコードをスキャンするようにSpringに指示します。

15
Sachin Sharma
<context:annotation-config>

Only は@Autowiredアノテーションと@Qualiferアノテーションを解決します。つまり、 Dependency Injection についてです。アノテーションを介してDIを解決します。

<context:annotation-config>要素を宣言した場合でも、注意してください。 あなたは yourクラスをとにかく宣言しなければなりません。

  • XML:<bean>
  • @注釈:@コンポーネント、@サービス、@リポジトリ、@コントローラ
  • JavaConfig:@Configuration、@ Bean

今すぐ

<context:component-scan>

それは2つのことをします:

  • これは、@ Component、@ Service、@ Repository、@ Controller、および@Configurationでアノテーションが付けられたすべてのクラスをスキャンしてBeanを作成します。
  • <context:annotation-config>と同じ働きをします。

したがって、<context:component-scan>を宣言しても、もう<context:annotation-config>も宣言する必要はありません。

それで全部です

一般的なシナリオは、たとえばXMLを介してBeanのみを宣言し、アノテーションを介してDIを解決するなどです。

<bean id="serviceBeanA" class="com.something.CarServiceImpl" />
<bean id="serviceBeanB" class="com.something.PersonServiceImpl" />
<bean id="repositoryBeanA" class="com.something.CarRepository" />
<bean id="repositoryBeanB" class="com.something.PersonRepository" />

<constructor-arg><property>については何も宣言していません。DIは@Autowiredを介して独自のクラスで構成されています。つまり、サービスはそのリポジトリコンポーネントに@Autowiredを使用し、リポジトリはJdbcTemplate、DataSource etc..comには@Autowiredを使用します。

11
Manuel Jordan
<context:component-scan /> implicitly enables <context:annotation-config/>

あなたの設定で<context:component-scan base-package="..." annotation-config="false"/>を試してみてください。@Service、@Repository、@Componentはうまく動きますが、@ Autowired、@ Resourceそして@Injectは動きません。

つまり、AutowiredAnnotationBeanPostProcessorは有効にならず、SpringコンテナはAutowiringアノテーションを処理しません。

6
Lovababu
<context:annotation-config/> <!-- is used to activate the annotation for beans -->
<context:component-scan base-package="x.y.MyClass" /> <!-- is for the Spring IOC container to look for the beans in the base package. -->

もう1つ注意すべき重要な点は、context:component-scancontext:annotation-configを暗黙的に呼び出してBeanの注釈をアクティブにすることです。 context:component-scanが自動的にアノテーションをアクティブにしたくない場合は、context:component-scanのannotation-config要素をfalseに設定し続けることができます。

要約する:

<context:annotation-config/> <!-- activates the annotations --> 
<context:component-scan base-package="x.y.MyClass" /> <!-- activates the annotations + register the beans by looking inside the base-package -->
5
Abdullah Khan

<context:component-scan/>カスタムタグは、JavaパッケージをスキャンしてクラスパスからBean定義を登録するという主な役割を除いて、と同じ一連のBean定義を登録します。

何らかの理由でこのデフォルトのBean定義の登録を避けたい場合は、component-scanで追加の "annotation-config"属性を指定するのがこの方法です。

<context:component-scan basePackages="" annotation-config="false"/>

参照: http://www.Java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html

0
Abhishek Gaur

<context:component-scan base-package="package name" />

これは、私のパッケージにそれらのBeanクラスをスキャンするBeanクラスがあることをコンテナに伝えるために使用されます。 Beanの上にあるコンテナごとにBeanクラスをスキャンするには、次のようなステレオタイプの注釈を1つ記述する必要があります。

@Component@Service@Repository@Controller

<context:annotation-config />

XMLで明示的にBeanタグを記述したくない場合は、Beanに自動配線があるかどうかコンテナがどのように認識するかこれは@Autowiredアノテーションを使うことによって可能です。 context:annotation-configによって、私のBeanに自動配線があることをコンテナに知らせる必要があります。

0

補足として、@ComponentScanを使用して、注釈方法で<context:component-scan>を使用できます。

spring.io でも説明されています

@Configurationクラスで使用するコンポーネントスキャンディレクティブを構成します。 Spring XMLの要素と並行してサポートを提供します。

注意すべき点として、Spring Bootを使用している場合は、@ SpringBootApplicationアノテーションを使用することで@Configurationと@ComponentScanを暗示できます。

0
Gearon

<context:annotation-config>

これはSpringに、私はSpring BeanとしてAnnotated beanを使うつもりであり、それらはspring config xmlファイルで宣言するのではなく@Autowiredアノテーションを通して配線されることを伝えます。

<context:component-scan base-package="com.test...">

これはSpringコンテナに、アノテーション付きのBeanの検索をどこから始めるかを指示します。ここでspringはベースパッケージのすべてのサブパッケージを検索します。

0

あなたは春のコンテキストスキーマファイルでより多くの情報を見つけることができます。以下はspring-context-4.3.xsdにあります

<conxtext:annotation-config />
Activates various annotations to be detected in bean classes: Spring's @Required and
@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's
@PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.

Note: This tag does not activate processing of Spring's @Transactional or EJB 3's
@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
tag for that purpose.
<context:component-scan>
Scans the classpath for annotated components that will be auto-registered as
Spring beans. By default, the Spring-provided @Component, @Repository, @Service, @Controller, @RestController, @ControllerAdvice, and @Configuration stereotypes    will be detected.

Note: This tag implies the effects of the 'annotation-config' tag, activating @Required,
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit
annotations in the component classes, which is usually desired for autodetected components
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
this default behavior, for example in order to use custom BeanPostProcessor definitions
for handling those annotations.

Note: You may use placeholders in package paths, but only resolved against system
properties (analogous to resource paths). A component scan results in new bean definitions
being registered; Spring's PropertySourcesPlaceholderConfigurer will apply to those bean
definitions just like to regular bean definitions, but it won't apply to the component
scan settings themselves.
0
coffeenjava