你的位置:首页 > Java教程

[Java教程][转载]Difference between context:annotation


在国外看到详细的说明一篇,非常浅显透彻。转给国内的筒子们:-)

 

原文标题:

Spring中的<context:annotation-config>与<context:component-scan>到底有什么不同?

 

原文出处:http://stackoverflow.com/a/7456501

 

<context:annotation-config> is used to activate annotations in beans already registered in the application context (no matter if they were defined with

<context:component-scan> can also do what <context:annotation-config> does but <context:component-scan> also scans packages to find and register beans within the application context.

I'll use some examples to show the differences/similarities.

Lets start with a basic setup of three beans of type AB and C, with B and C being injected into A.

 1 package com.xxx; 2 public class B { 3  public B() { 4   System.out.println("creating bean B: " + this); 5  } 6 } 7  8 package com.xxx; 9 public class C {10  public C() {11   System.out.println("creating bean C: " + this);12  }13 }14 15 package com.yyy;16 import com.xxx.B;17 import com.xxx.C;18 public class A { 19  private B bbb;20  private C ccc;21  public A() {22   System.out.println("creating bean A: " + this);23  }24  public void setBbb(B bbb) {25   System.out.println("setting A.bbb with " + bbb);26   this.bbb = bbb;27  }28  public void setCcc(C ccc) {29   System.out.println("setting A.ccc with " + ccc);30   this.ccc = ccc; 31  }32 }

 

With the following

1 <bean id="bBean" class="com.xxx.B" />2 <bean id="cBean" class="com.xxx.C" />3 <bean id="aBean" class="com.yyy.A">4  <property name="bbb" ref="bBean" />5  <property name="ccc" ref="cBean" />6 </bean>

 

Loading the context produces the following output:

creating bean B: com.xxx.B@c2ff5creating bean C: com.xxx.C@1e8a1f6creating bean A: com.yyy.A@1e152c5setting A.bbb with com.xxx.B@c2ff5setting A.ccc with com.xxx.C@1e8a1f6

OK, this is the expected output. But this is "old style" Spring. Now we have annotations so lets use those to simplify the

 

First, lets autowire the bbb and ccc properties on bean A like so:

 1 package com.yyy; 2 import org.springframework.beans.factory.annotation.Autowired; 3 import com.xxx.B; 4 import com.xxx.C; 5 public class A {  6  private B bbb; 7  private C ccc; 8  public A() { 9   System.out.println("creating bean A: " + this);10  }11  @Autowired12  public void setBbb(B bbb) {13   System.out.println("setting A.bbb with " + bbb);14   this.bbb = bbb;15  }16  @Autowired17  public void setCcc(C ccc) {18   System.out.println("setting A.ccc with " + ccc);19   this.ccc = ccc;20  }21 }

This allows me to remove the following rows from the

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

My

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

When I load the context I get the following output:

creating bean B: com.xxx.B@5e5a50creating bean C: com.xxx.C@54a328creating bean A: com.yyy.A@a3d4cf

OK, this is wrong! What happened? Why aren't my properties autowired?

Well, annotations are a nice feature but by themselves they do nothing whatsoever. They just annotate stuff. You need a processing tool to find the annotations and do something with them.

<context:annotation-config> to the rescue. This activates the actions for the annotations that it finds on the beans defined in the same application context where itself is defined.

If I change my

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

 

when I load the application context I get the proper result:

creating bean B: com.xxx.B@15663a2creating bean C: com.xxx.C@cd5f8bcreating bean A: com.yyy.A@157aa53setting A.bbb with com.xxx.B@15663a2setting A.ccc with com.xxx.C@cd5f8b

OK, this is nice, but I've removed two rows from the

So let's remove the

 1 package com.xxx; 2 import org.springframework.stereotype.Component; 3 @Component 4 public class B { 5  public B() { 6   System.out.println("creating bean B: " + this); 7  } 8 } 9 10 package com.xxx;11 import org.springframework.stereotype.Component;12 @Component13 public class C {14  public C() {15   System.out.println("creating bean C: " + this);16  }17 }18 19 package com.yyy;20 import org.springframework.beans.factory.annotation.Autowired;21 import org.springframework.stereotype.Component;22 import com.xxx.B;23 import com.xxx.C;24 @Component25 public class A { 26  private B bbb;27  private C ccc;28  public A() {29   System.out.println("creating bean A: " + this);30  }31  @Autowired32  public void setBbb(B bbb) {33   System.out.println("setting A.bbb with " + bbb);34   this.bbb = bbb;35  }36  @Autowired37  public void setCcc(C ccc) {38   System.out.println("setting A.ccc with " + ccc);39   this.ccc = ccc;40  }41 }

 

While in the

1 <context:annotation-config />

We load the context and the result is... Nothing. No beans are created, no beans are autowired. Nothing!

That's because, as I said in the first paragraph, the <context:annotation-config /> only works on beans registered within the application context. Because I removed the <context:annotation-config /> has no "targets" to work on.

But that won't be a problem for <context:component-scan> which can scan a package for "targets" to work on. Let's change the content of the

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

 

When I load the context I get the following output:

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

Hmmmm... something is missing. Why?

If you look closelly at the classes, class A has package com.yyy but I've specified in the <context:component-scan> to use package com.xxx so this completely missed my A class and only picked up B and C which are on the com.xxx package.

To fix this, I add this other package also:

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

 

and now we get the expected result:

creating bean B: com.xxx.B@cd5f8bcreating bean C: com.xxx.C@15ac3c9creating bean A: com.yyy.A@ec4a87setting A.bbb with com.xxx.B@cd5f8bsetting A.ccc with com.xxx.C@15ac3c9

And that's it! Now you don't have

As a final example, keeping the annotated classes AB and C and adding the following to the

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

 

We still get the correct result:

creating bean B: com.xxx.B@157aa53creating bean C: com.xxx.C@ec4a87creating bean A: com.yyy.A@1d64c37setting A.bbb with com.xxx.B@157aa53setting A.ccc with com.xxx.C@ec4a87

Even if the bean for class A isn't obtained by scanning, the processing tools are still applied by <context:component-scan> on all beans registered in the application context, even for A which was manually registered in the

But what if we have the following <context:annotation-config /> and <context:component-scan>?

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

 

No, no duplications, We again get the expected result:

creating bean B: com.xxx.B@157aa53creating bean C: com.xxx.C@ec4a87creating bean A: com.yyy.A@1d64c37setting A.bbb with com.xxx.B@157aa53setting A.ccc with com.xxx.C@ec4a87

That's because both tags register the same processing tools (<context:annotation-config /> can be omitted if <context:component-scan> is specified) but Spring takes care of running them only once.

Even if you register the processing tools yourself multiple times, Spring will still make sure they do their magic only once; this

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

 

will still generate the following result:

creating bean B: com.xxx.B@157aa53creating bean C: com.xxx.C@ec4a87creating bean A: com.yyy.A@25d2b2setting A.bbb with com.xxx.B@157aa53setting A.ccc with com.xxx.C@ec4a87

OK, that about raps it up.

I hope this information along with the responses from @Tomasz Nurkiewicz and @Sean Patrick Floyd are all you need to understand how <context:annotation-config> and <context:component-scan> work.