Spring <context:annotation-config> 與<context-component-scan> 的作用
<context:annotation-config> 是用於激活那些已經在spring容器裏註冊過的bean(無論是通過xml的方式還是通過package sanning的方式)上面的註解。
<context:component-scan>除了具有<context:annotation-config>的功能之外,<context:component-scan>還可以在指定的package下掃描以及註冊javabean 。
例子:有三個類 A,B,C,並且B,C的對象被註入到A中.
package com.spring; public class B { public B() { System.out.println("creating bean B: " + this); } } package com.spring; public class C { public C() { System.out.println("creating bean C: " + this); } } package com.spring2; import com.spring.B; import com.spring.C; public class A { private B b; private C c; public A() { System.out.println("creating bean A: " + this); } public void setBbb(B b) { System.out.println("setting A.b with " + b); this.b = b; } public void setC(C c) { System.out.println("setting A.c with " + c); this.c = c; } }
在applicationContext.xml中加入下面的配置 :
<bean id="b"class="com.spring.B"/> <bean id="c"class="com.spring.C"/> <bean id="a"class="com.spring2.A"> <property name="b" ref="b"/> <property name="c" ref="c"/> </bean>
加載applicationContext.xml配置文件,將得到下面的結果:
creating bean B: com.spring.B@c2ee6
creating bean C: com.spring.C@1e8a1
creating bean A: com.yyy.A@1e1d435
setting A.b with com.spring.B@c2ff5
setting A.c with com.spring.C@1e8a
下面通過註解的方式來簡化我們的xml配置文件
首先,我們使用autowire的方式將對象b和c註入到A中:
package com.spring2; import org.springframework.beans.factory.annotation.Autowired; import com.spring.B; import com.spring.C; public class A { private B b; private C c; public A() { System.out.println("creating bean A: " + this); } @Autowired public void setB(B b) { System.out.println("setting A.b with " + b); this.b = b; } @Autowired public void setC(C c) { System.out.println("setting A.c with " + c); this.c = c; } }
在applicationContext.xml配置文件中去除屬性<property>就簡化為下面的樣子了
<bean id="b"class="com.spring.B"/> <bean id="c"class="com.spring.C"/> <bean id="a"class="com.spring2.A"/>
當我們加載applicationContext.xml配置文件之後,將得到下面的結果:
creating bean B: com.xxx.B@5e5a
creating bean C: com.xxx.C@54a3
creating bean A: com.yyy.A@a3d4
OK, ClassA中顯然沒有註入屬性,結果是錯誤的的,究竟是因為什麽呢?為什麽我們的屬性沒有被註入進去呢?
是因為註解本身並不能夠做任何事情,它們只是最基本的組成部分,我們需要能夠處理這些註解的處理工具來處理這些註解。
這就是<context:annotation-config> 所做的事情,用於激活那些已經在spring容器裏註冊過的bean
我們將applicationContext.xml配置文件作如下修改:
<context:annotation-config /> <bean id="b"class="com.spring.B"/> <bean id="c"class="com.spring.C"/> <bean id="a"class="com.spring2.A"/>
這回,當我們加載applicationContext.xml配置文件之後,將得到下面的結果:
creating bean B: com.spring.B@178ace
creating bean C: com.spring.C@af0cdld
creating bean A: com.spring2.A@jalfj012
setting A.b with com.spring.B@15663a2
setting A.c with com.spring.C@cd5f8b
和期望的結果一致
但是如果我們將代碼作如下修改:
package com.spring; import org.springframework.stereotype.Component; @Component public class B { public B() { System.out.println("creating bean B: " + this); } } package com.spring; import org.springframework.stereotype.Component; @Component public class C { public C() { System.out.println("creating bean C: " + this); } } package com.spring2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.spring.B; import com.spring.C; @Component public class A { private B b; private C c; public A() { System.out.println("creating bean A: " + this); } @Autowired public void setB(B b) { System.out.println("setting A.b with " + bbb); this.b = b; } @Autowired public void setC(C c) { System.out.println("setting A.ccc with " + c); this.c = c; } }
applicationContext.xml配置文件修改為:
<context:annotation-config />
當我們加載applicationContext.xml配置文件之後,卻沒有任何輸出,這是為什麽呢?
那是因為<context:annotation-config />僅能夠在已經在已經註冊過的bean上面起作用。
對於沒有在spring容器中註冊的bean,它並不能執行任何操作。
而<context:component-scan>除了具有
<context:annotation-config />的功能之外,還具有自動將帶有@component,@service,@Repository等註解的對象註冊到spring容器中的功能。
我們將applicationContext.xml配置文件作如下修改:
<context:component-scan base-package="com.spring"/>
當我們加載applicationContext.xml的時候,會得到下面的結果:
creating bean B: com.x.B@1be0f
creating bean C: com.x.C@80d1
這是什麽原因呢?
是因為我們僅僅掃描了com.spring包及其子包的類,而class A是在com.spring2包下,所以就掃描不到了
下面我們在applicationContext.xml中把com.spring2也加入進來:
<context:component-scan base-package="com.spring,com.spring2"/>
然後加載applicationContext.xml就會得到下面的結果:
creating bean B: com.spring.B@cd5f8b
creating bean C: com.spring.C@15ac3c9
creating bean A: com.spring2.A@ec4a87
setting A.b with com.spring.B@cd5f8b
setting A.c with com.spring.C@15ac3c9
回頭看下我們的applicationContext.xml文件,已經簡化為兩行context:component-scan了,是不是很簡單?
那如果我們在applicationContext.xml手動加上下面的配置,
也就是說既在applicationContext.xml中手動的註冊了A的實例對象,同時,通過component-scan去掃描並註冊B,C的對象,如下
<context:component-scan base-package="com.spring"/> <bean id="a"class="com.spring2.A"/>
結果仍是正確的:
creating bean B: com.spring.B@157aa53
creating bean C: com.spring.C@ec4a87
creating bean A: com.spring2.A@1d64c37
setting A.b with com.spring.B@157aa53
setting A.c with com.spring.C@ec4a87
雖然class A並不是通過掃描的方式註冊到容器中的 ,
但是<context:component-scan> 所產生的的處理那些註解的處理器工具,會處理所有綁定到容器上面的bean,不管是通過xml手動註冊的還是通過scanning掃描註冊的。
那麽,如果我們通過下面的方式呢?我們既配置了<context:annotation-config />,又配置了<context:component-scan base-package="com.spring" />,它們都具有處理在容器中註冊的bean裏面的註解的功能。會不會出現重復註入的情況呢?
<context:annotation-config /> <context:component-scan base-package="com.spring"/> <bean id="a"class="com.spring2.A"/>
不用擔心,不會出現的,結果如下:
creating bean B: com.spring.B@157aa
creating bean C: com.spring.C@ec4a8
creating bean A: com.spring2.A@1d64
setting A.bbb with com.spring.B@157a
setting A.ccc with com.spring.C@ec4a
因為<context:annotation-config />和 <context:component-scan>同時存在的時候,前者會被忽略。
也就是那些@autowire,@resource等註入註解只會被註入一次
哪怕是你手動的註冊了多個處理器,spring仍然只會處理一次:
<context:annotation-config /> <context:component-scan base-package="com.spring" /> <bean id="a" class="com.spring2.A" /> <bean id="b1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> <bean id="b2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> <bean id="b3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> <bean id="b4" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
結果仍是正確的:
creating bean B: com.spring.B@157aa53
creating bean C: com.spring.C@ec4a87
creating bean A: com.spring2.A@25d2b2
setting A.b with com.spring.B@157aa53
setting A.c with com.spring.C@ec4a87
Spring <context:annotation-config> 與<context-component-scan> 的作用