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


690

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

私が何を読んでから、それらは異なる扱いするように見える注釈を@Required@Autowired対など@Component@Repository@Service、だけでなく、私は彼らが同じレジスタの何を読んでからなど)豆ポストプロセッサクラスを。

もっと私を混乱させ、そこにあるannotation-config 属性<context:component-scan>

誰かがこれらのタグにいくつかの光を当てることができますか?似ている点、違う点、一方が他方に取って代わられている、それらが互いに完了している、どちらか一方が必要ですか?



要約すると、component-scan可能な限り使用し ます。
ジェリーチン

回答:


1419

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

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

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

タイプの3つの豆の基本的なセットアップを開始することができますABそしてC、とBCに注入されますA

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

OK、これは予想される出力です。しかし、これは「古いスタイル」の春です。これで注釈ができたので、それらを使用して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

OK、これでいいのですが、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は作成されず、自動ワイヤリングも行われません。何もない!

これは、最初の段落で述べたように<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

うーん...何かが欠けています。どうして?

あなたはクラスでcloselly見ると、クラスがAパッケージを持っているcom.yyyが、私はで指定した<context:component-scan>パッケージを使用するためにcom.xxx、これは完全に私逃したので、Aクラスを唯一のピックアップBCその上にあるcom.xxxパッケージ。

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

<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に手動で登録されていたとして<context:component-scan>も、アプリケーションコンテキストに登録されているすべてのBeanに処理ツールが適用されAます。

しかし、我々は、以下のXMLを持っている場合、我々は両方を指定したので、豆を重複してしまいます<context:annotation-config /><context:component-scan>

<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

わかりました。それで終わりです。

この情報と、@ Tomasz Nurkiewiczと@Sean Patrick Floydからの回答が、方法<context:annotation-config><context:component-scan>動作を理解するために必要なすべてであることを願っています 。


8
引用:「<context:component-scan>が指定されている場合、<context:annotation-config />は省略できます」。では、なぜアノテーション設定を使用するのでしょうか?なぜそれが存在するのですか?
CodeClimber 2013年

2
正解です。簡潔でわかりやすい短い明確な例のようなものはありません。すべてを一度に理解した。
ジジッシュ2013年

19
Springマニュアルを全部書いてくれたらいいのに!Spring Frameworkの混乱に関連するあらゆるものについての最も良い説明。ありがとう。
eskalera 2013年

7
とてもシンプルで優れた説明。答えを得る以外に、物事を伝える良い方法も学びました:)
Amir Al

2
あなたの書き方は初心者にとって非常に理解しやすいものです。基本的な春の本を書いて頂けたら幸いです。買うと約束する。
emeraldhieu 2014年

167

どの注釈がどの宣言によってピックアップされるかについて、この素晴らしい要約を見つけました。それを研究すること<context:component-scan/>により<context:annotation-config/>、はによって認識される注釈のスーパーセットを認識します。すなわち、

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

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


16
@Tomaszリンクダウン:(
Anand Rockzz

95

Springでは、次の2つのことが可能です。

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

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

手動のXML構成をエスケープするためのステップは次のとおりです。

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


結論として:

  • <context:annotation-config />@Autowiredアノテーションを使用できるようにするために使用されます
  • <context:component-scan /> 特定のBeanの検索と自動配線の試行を判別するために使用されます。

1
どういうわけかcomponent-scanを使用してannotation-configを使用することは可能ですか?
Koray Tugay

コンテキスト:annotation-configタグでannotation-config = "false"を使用します。
サラ

38

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

<context:component-scan> XMLを使用せずにBeanを定義するためのものです

詳細については、以下をお読みください。


さらに説明していただけますか?使用する場合<context:component-scan>、XMLを使用してBean定義をオーバーライドできませんか?
user938214097 2011

@ user938214097 Beanは、XMLで、またはコンポーネントスキャンを使用したアノテーションで定義できます
Sean Patrick Floyd

使用するだけで十分<context:component-scan>ですか?使用しない場合、何かを失い<context:annotation-config>ますか?
user938214097 2011

@Tomaszが答えたようです
Sean Patrick Floyd

31

2つの違いは本当に簡単です!。

<context:annotation-config /> 

Beanのみのプロパティとコンストラクターの関連付けに制限されている注釈を使用できるようにします。

どこに

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

すべて有効<context:annotation-config />ステレオタイプなど..を使用しての追加により、行うことができますが@Component@Service@Repository。そのため、コンストラクタやプロパティだけに制限されず、Bean全体をワイヤリングできます。


31

<context:annotation-config> Spring config xmlにすでに登録されているBeanのアノテーションをスキャンしてアクティブ化します。

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


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

@RequiredRequiredAnnotationBeanPostProcessor 処理ツールを
有効にする@AutowiredAutowiredAnnotationBeanPostProcessor処理ツールを有効に する

注:アノテーション自体は何もする必要はありません。コアプロセスを担当する、その下のクラスである処理ツールが必要です。


@ Repository、@ Service、および@Controllerは@Componentであり、クラスレベル対象としています

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

注釈へのXMLの移行


15

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

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

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


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

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

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

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

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


14
<context:annotation-config>

@Autowired@Qualiferアノテーションのみを解決します。それだけです。依存性注入に関するものです。同じ働きをするアノテーションは他にもありますが、私はその方法を考えていますが@Inject、アノテーションを通じてDIを解決しようとしています。

<context:annotation-config>要素を宣言した場合でも、Beanの方法をクラスに宣言する必要があることに注意してください。3つのオプションがあることに注意してください。

  • 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などのコンポーネントに@Autowiredを使用することを意味します。


1
素晴らしい説明ありがとうございます。@Manuel Jordan
BALS

7
<context:component-scan /> implicitly enables <context:annotation-config/>

してみてください<context:component-scan base-package="..." annotation-config="false"/>、あなたの構成で@Service、@Repository、@Componentは、正常に動作しますが、リソース@、Autowired @@Injectは機能しません。

これは、AutowiredAnnotationBeanPostProcessorが有効にならず、SpringコンテナがAutowiringアノテーションを処理しないことを意味します。


これは、<context:component-scan />が暗黙的に<context:annotation-config />を有効にすることを理解するのに役立ちました。つまり、Bean定義をスキャンするだけでなく、必要な注入も行います。annotation-config = "false"を試してみましたが、<context:annotation-config />を使用して明示的に設定しない限り、インジェクションは機能しませんでした。ついに私の理解は以前より良くなりました!
CuriousMind 2016

5
<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. -->

注意すべき他の重要な点は、context:component-scan暗黙的にを呼び出して、context:annotation-configBeanの注釈をアクティブにすることです。context:component-scan暗黙的に注釈をアクティブにしたくない場合は、context:component-scantoの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 -->

1

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

これは、パッケージにBeanクラスがあることをコンテナに通知するために使用されます。これらのBeanクラスをスキャンします。Beanの上にあるコンテナーによってBeanクラスをスキャンするには、次のようなステレオタイプアノテーションの1つを記述する必要があります。

@Component@Service@Repository@Controller

<context:annotation-config />

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


0

<context:component-scan/>カスタムタグは、クラスパスからBean定義をJavaパッケージをスキャンし、登録のその第一の責任は別に、によって行われているように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

<context:annotation-config>

これは、Springに注釈付きBeanをSpring Beanとして使用することを伝え、これらはBean @Autowiredアノテーション xmlファイルで宣言する代わりにアノテーションワイヤリングさます。

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

これにより、Springコンテナに、注釈が付けられたBeanの検索を開始する場所が通知されます。ここで、春は基本パッケージのすべてのサブパッケージを検索します。


0

詳細については、Springコンテキストスキーマファイルを参照してください。以下は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

補足として、あなたは使用@ComponentScanすることができます<context:component-scan>アノテーションの方法で。

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

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

Spring Bootを使用している場合、@ SpringBootApplicationアノテーションを使用すると、@ Configurationと@ComponentScanを暗黙的に指定できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.