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

annotation-config和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.zr.pojo;


public class B {
    public B() {
        System.out.println("creating bean B: " + this);
    }
}
package com.zr.pojo;

public class C {
    public C() {
        System.out.println("creating bean C: " + this);
    }
}
package com.zr.pojo1;

import com.zr.pojo.B;
import com.zr.pojo.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中加入下面的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bBean" class="com.zr.pojo.B"/>
    <bean id="cBean" class="com.zr.pojo.C"/>

    <bean id="aBean" class="com.zr.pojo1.A">
        <property name="bbb" ref="bBean"/>
        <property name="ccc" ref="cBean"/>
    </bean>

</beans>

加載applicationContext.xml配置文件,將得到下面的結果:

creating bean B: com.zr.pojo.B@6483f5ae
creating bean C: com.zr.pojo.C@282003e1
creating bean A: com.zr.pojo1.A@7fad8c79
setting A.bbb with com.zr.pojo.B@6483f5ae
setting A.ccc with com.zr.pojo.C@282003e1

完全通過xml的方式,太過時了

下面通過註解的方式來簡化我們的xml配置文件

首先,我們使用@Autowired的方式將對象bbb和ccc注入到A中

package com.zr.pojo1;

import com.zr.pojo.B;
import com.zr.pojo.C;
import org.springframework.beans.factory.annotation.Autowired;

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 >

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bBean" class="com.zr.pojo.B"/>
    <bean id="cBean" class="com.zr.pojo.C"/>
    <bean id="aBean" class="com.zr.pojo1.A"/>

</beans>

加載applicationContext.xml配置文件之後,得到下面的結果

creating bean B: com.zr.pojo.B@768b970c
creating bean C: com.zr.pojo.C@290dbf45
creating bean A: com.zr.pojo1.A@12028586

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

是因爲註解本身並不能夠做任何事情,它們只是最基本的組成部分

我們需要能夠處理這些註解的處理工具來處理這些註解

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

將applicationContext.xml配置文件作如下修改

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    
    <context:annotation-config/>
    
    <bean id="bBean" class="com.zr.pojo.B"/>
    <bean id="cBean" class="com.zr.pojo.C"/>
    <bean id="aBean" class="com.zr.pojo1.A"/>

</beans>

加載applicationContext.xml配置文件之後,將得到下面的結果:

creating bean B: com.zr.pojo.B@36c88a32
creating bean C: com.zr.pojo.C@1d119efb
creating bean A: com.zr.pojo1.A@35047d03
setting A.ccc with com.zr.pojo.C@1d119efb
setting A.bbb with com.zr.pojo.B@36c88a32

結果正確了

但是如果將代碼作如下修改

package com.zr.pojo;

import org.springframework.stereotype.Component;

@Component
public class B {
    public B() {
        System.out.println("creating bean B: " + this);
    }
}
package com.zr.pojo;

import org.springframework.stereotype.Component;

@Component
public class C {
    public C() {
        System.out.println("creating bean C: " + this);
    }
}
package com.zr.pojo1;

import com.zr.pojo.B;
import com.zr.pojo.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@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配置文件修改爲:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
</beans>

當加載applicationContext.xml配置文件之後,卻沒有任何輸出,這是爲什麼呢?

因爲<context:annotation-config />僅能夠在已經在已經註冊過的bean上面起作用

對於沒有在spring容器中註冊的bean,它並不能執行任何操作

但是不用擔心,< context:component-scan >除了具有<context:annotation-config />的功能之外,還具有自動將帶有@component,@service,@Repository等註解的對象註冊到spring容器中的功能

我們將applicationContext.xml配置文件作如下修改:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.zr.pojo"/>
    <context:component-scan base-package="com.zr.pojo1"/>
</beans>

加載applicationContext.xml就會得到下面的結果:

creating bean B: com.zr.pojo.B@6b81ce95
creating bean C: com.zr.pojo.C@16293aa2
creating bean A: com.zr.pojo1.A@2d7275fc
setting A.bbb with com.zr.pojo.B@6b81ce95
setting A.ccc with com.zr.pojo.C@16293aa2

結果正確

回頭看下applicationContext.xml文件,已經簡化爲兩行context:component-scan了,是不是很簡單?

那如果在applicationContext.xml手動加上下面的配置,也就是說

既在applicationContext.xml中手動的註冊了A的實例對象,

同時,通過component-scan去掃描並註冊B,C的對象,如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.zr.pojo"/>
    <bean id="aBean" class="com.zr.pojo1.A"/>
</beans>

結果正確:

creating bean B: com.zr.pojo.B@6b81ce95
creating bean C: com.zr.pojo.C@16293aa2
creating bean A: com.zr.pojo1.A@2d7275fc
setting A.ccc with com.zr.pojo.C@16293aa2
setting A.bbb with com.zr.pojo.B@6b81ce95

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

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

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config />
    <context:component-scan base-package="com.zr.pojo"/>
    <bean id="aBean" class="com.zr.pojo1.A"/>
</beans>

結果如下,沒有出現:

creating bean B: com.zr.pojo.B@37afeb11
creating bean C: com.zr.pojo.C@2d7275fc
creating bean A: com.zr.pojo1.A@79e2c065
setting A.bbb with com.zr.pojo.B@37afeb11
setting A.ccc with com.zr.pojo.C@2d7275fc

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

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

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config />
    <context:component-scan base-package="com.zr.pojo"/>
    <bean id="aBean" class="com.zr.pojo1.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" />
</beans>

結果仍是正確的:

creating bean B: com.zr.pojo.B@515aebb0
creating bean C: com.zr.pojo.C@399f45b1
creating bean A: com.zr.pojo1.A@3a93b025
setting A.ccc with com.zr.pojo.C@399f45b1
setting A.bbb with com.zr.pojo.B@515aebb0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章