1. 程式人生 > ><context:annotation-config> 和 <context:component-scan>的區別

<context:annotation-config> 和 <context:component-scan>的區別

<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 。

下面我們通過例子來詳細檢視他們的區別,有三個class   A,B,C,並且B,C的物件被注入到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; 
  }
}
複製程式碼

 

在applicationContext.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>

 

載入applicationContext.xml配置檔案,將得到下面的結果:

creating bean B: [email protected]
creating bean C: [email protected]
creating bean A: [email protected]
setting A.bbb with [email protected]
setting A.ccc with [email protected]

OK, 這個結果沒什麼好說的,就是完全通過xml的方式,不過太過時了,下面通過註解的方式來簡化我們的xml配置檔案

 

下邊看看怎麼使用<context:annotation-config>和 <context:component-scan>

首先,我們使用autowire的方式將物件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;
  }
}
複製程式碼

 

然後applicationContext.xml配置檔案去除屬性<property>就簡化為下面的樣子了

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

 

當我們載入applicationContext.xml配置檔案之後,將得到下面的結果:

creating bean B: [email protected]
creating bean C: [email protected]
creating bean A: [email protected]

 

OK, ClassA中顯然沒有注入屬性,結果是錯誤的的,究竟是因為什麼呢?為什麼我們的屬性沒有被注入進去呢?

是因為註解本身並不能夠做任何事情,它們只是最基本的組成部分,我們需要能夠處理這些註解的處理工具來處理這些註解。

這就是<context:annotation-config> 所做的事情,用於啟用那些已經在spring容器裡註冊過的bean

我們將applicationContext.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"/>

 

這回,當我們載入applicationContext.xml配置檔案之後,將得到下面的結果:

creating bean B: [email protected]
creating bean C: [email protected]
creating bean A: [email protected]
setting A.bbb with [email protected]
setting A.ccc with [email protected]

 

OK, 結果正確了

但是如果我們將程式碼作如下修改:

複製程式碼
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;
  }
}
複製程式碼

 

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.xxx"/>

當我們載入applicationContext.xml的時候,會得到下面的結果:

creating bean B: [email protected]
creating bean C: [email protected]

 

這是什麼原因呢?

是因為我們僅僅掃描了com.xxx包及其子包的類,而class  A是在com.yyy包下,所以就掃描不到了

下面我們在applicationContext.xml中把com.yyy也加入進來:

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

 

然後載入applicationContext.xml就會得到下面的結果:

creating bean B: [email protected]
creating bean C: [email protected]
creating bean A: [email protected]
setting A.bbb with [email protected]
setting A.ccc with [email protected]

 

哇,結果正確啦 !

回頭看下我們的applicationContext.xml檔案,已經簡化為兩行context:component-scan了,是不是很簡單?

 

那如果我們在applicationContext.xml手動加上下面的配置,

也就是說既在applicationContext.xml中手動的註冊了A的例項物件,同時,通過component-scan去掃描並註冊B,C的物件,如下

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

 

結果仍是正確的:

creating bean B: [email protected]
creating bean C: [email protected]
creating bean A: [email protected]
setting A.bbb with [email protected]
setting A.ccc with [email protected]

 

雖然class A並不是通過掃描的方式註冊到容器中的 ,

但是<context:component-scan> 所產生的的處理那些註解的處理器工具,會處理所有繫結到容器上面的bean,不管是通過xml手動註冊的還是通過scanning掃描註冊的。

 

那麼,如果我們通過下面的方式呢?我們既配置了<context:annotation-config />,又配置了<context:component-scan base-package="com.xxx" />,它們都具有處理在容器中註冊的bean裡面的註解的功能。會不會出現重複注入的情況呢?

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

 

不用擔心,不會出現的,結果如下:

creating bean B: [email protected]
creating bean C: [email protected]
creating bean A: [email protected]
setting A.bbb with [email protected]
setting A.ccc with [email protected]

 

因為<context:annotation-config />和 <context:component-scan>同時存在的時候,前者會被忽略。

也就是那些@autowire,@resource等注入註解只會被注入一次

哪怕是你手動的註冊了多個處理器,spring仍然只會處理一次:

複製程式碼
<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: [email protected]
creating bean C: [email protected]
creating bean A: [email protected]
setting A.bbb with [email protected]
setting A.ccc with [email protected]