質問: <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>属性があります。誰かがこれらのタグに光を当てることはできますか?似ているもの、違うもの、他のものに取って代わられるもの、お互いを完成させるもの、どちらか一方が必要なのか、両方?
回答: <context:annotation-config>は、アプリケーションコンテキストにすでに登録されているbeanのアノテーションをアクティブにするために使用されます(xmlで定義されているかパッケージスキャンで定義されているかにかかわらず)。<context:component-scan>は<context:annotation-config>が行うこともできますが、<context:component-scan>はパッケージをスキャンしてアプリケーションコンテキスト内でbeanを見つけて登録することもできます。いくつかの例を使用して、相違点と類似点を示します。aとbがcにインジェクトされる、b、cとaの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 bbbのcccおよび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定義がなくなり、注釈が付きます。最後の例として、アノテーション付きクラスa、b、および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からの回答とともに、この情報がすべて揃っていることを願います。