天天看點

2.3 Bean裝配

1、spring容器成功啟動的條件

spring架構的類包都已放在應用程式的類路徑;

應用程式為spring提供完備的bean資訊;

bean的類都已放到應用程式的類路徑下。

2、bean配置資訊是bean的元素據資訊,由4個方面組成:

bean的實作類;

bean的屬性資訊(如資料源的連接配接數、使用者名、密碼);

bean的依賴關系,spring根據依賴關系配置完成bean間的裝配;

bean的行為配置(如生命周期範圍及生命周期各過程的回調函數)。

2.3 Bean裝配

2.3.1 bean基本配置

2.3 Bean裝配

bean命名      

      id為bean的名稱,通過容器的getbean("foo")擷取對應的bean,在容器中起到定位查找的作用,是外部程式和spring ioc容器進行互動的橋梁,class指定了bean對應的實作類。

        id(xml規定的特殊屬性)在ioc容器中必須唯一,還需滿足xml對id的命名規範:字母開始,後接字母、數字、連字元、下劃線、句号、冒号等完整結束符。逗号、空格這些非完整結束符是非法的。

        name屬性幾乎可用任何字元,

<bean name="#car" class="com.car"/>

        id和name都可指定多個名字,名字間用逗号、分号或空格分隔。使用者可用getbean("123")或另外兩種名字擷取ioc容器中的carbean。

<bean name="#car,123,$car" class="com.car"/>

        spring配置檔案不允許兩個相同id的<bean>;但允許相同name的<bean>,getbean時會傳回最後聲明的那個bean,後面的bean覆寫了前面同名的bean。so,盡量使用id而不是name命名的bean。

        如果id、name都未指定,如①<bean  class="com.car"/>,spring自動将全限定類名作為bean的名稱,可通過②getbean("com.car")擷取carbean,如果存在多個實作類相同的匿名<bean>即多個①處的bean,第一個bean通過②獲得,第二個bean通過getbean("com.car#1")獲得,以此類推。

2.3.2 依賴注入

1)屬性注入

    setxxx()方法,可選擇性、靈活性高,最常用。

    要求bean提供預設的構造函數,并未需要注入的屬性提供對應的setter方法。spring先調用bean的預設    構造函數執行個體化bean對象,然後通過反射調用setter方法注入屬性值。

【預設構造函數】

        預設構造函數不帶參。java規定如果類中沒有定義任何構造函數,jvm自動生成一個預設構造函數。反之,如果類中顯示定義了構造函數,jvm将不會自動生成。so,類中顯示定義了一個帶參構造函數,則需同時提供一個預設構造函數,否則屬性注入時将抛出異常。

        spring隻會檢查bean中是否有對應的setter,是否有對應屬性變量則不作要求。但一般約定俗成在bean中提供同名的屬性變量。

【java屬性變量】

        一般以小寫字母起頭,javabean允許大寫字母開頭,但必須滿足“變量的前兩個字母要麼全部大寫,要麼全部小寫”,brand、idcode合法,ic、idcode非法。

2)構造函數注入

        保證一些必要屬性在bean執行個體化時就得到設定,并確定bean執行個體在執行個體化後就可以使用。使用構造函數的前提是bean必須提供帶參的構造函數。

spring中構造函數注入的配置方式

注入時若比對的構造函數不止一個,預設比對最後一個構造函數。

bean存在多個構造函數時,盡可能顯示指定index、type。

①bytype:

<bean id="car1" class="com.smart.injection.car">

    <constructor-arg type="java.lang.string">

        <value>紅旗ca72</value>

    </constructor-arg>

    <constructor-arg type="double">

        <value>20000</value>

    <!--car

bean中必須有和此處一緻的構造函數(string、double參數的構造函數)-->

</bean>

 ②byindex:

<!--構造注入-索引比對入參-->

<bean id="carindex" class="com.smart.injection.car">

    <!--索引從0開始-->

    <constructor-arg index="0" value="紅旗ca72"/>

    <constructor-arg index="1" value="中國一汽"/>

    <constructor-arg index="2" value="20000"/>

    <!-- 必須有一個3個入參的構造函數,如果不止一個,将以最後一個構造函數為準 -->

 ③bytypeindex:

3)循環依賴問題

        spring容器順利執行個體化以構造函數方式配置的bean的前提是:bean構造函數引用的對象已經就緒。

如果兩個bean均通過構造函數注入,且通過構造函數入參引用對方,就會發生類似線程死鎖的循環依賴問題。

2.3.3 注入參數詳解

①字面值--可通過<value>元素标簽注入

字面值一般指可用字元串表示的值,如基本資料類型及其封裝類、string。spring内部編輯器可将以字元串表示的字面值轉化為内部變量的相應類型。

特殊處理标簽:

②引用其他bean--<ref>

<ref>元素引用bean的3個屬性:

    bean:引用同一容器或父容器的bean,最常見。

    local:隻能引用同一配置檔案的bean,可利用xml解析器自動檢驗引用的合法性。

    parent:引用父容器的bean。

③集合類型屬性

主要包括list、set、map、properties。

④通過util命名空間配置集合類型的bean

⑤簡化配置方式

⑤自動裝配 autowire=“<自動裝配類型>”

spring ioc容器了解容器中所有的bean資訊,通過java反射機制獲知實作類的結構資訊,開發人員可按照規則進行bean的字段裝配。

spring提供了4種自動裝配類型。<beans>元素标簽中的default-autowired屬性可配置為全局自動比對,預設為0,表示不啟用自動裝配。其他可選配置如下圖,byname,bytype,constructor,autodetect。

2.3 Bean裝配

減輕配置工作量,但造成配置檔案bean間關系不清楚,易引發潛在錯誤,是以實際項目建議少用。

2.3.4 bean作用域

spring2.0前僅有2個作用域:singleton和prototype。2.0開始針對webapplicationcontext新添了3個作用域。

2.3 Bean裝配

spring低版本由于隻有2個作用域,so采用singleton=“true|false”的配置方式,為向後相容,現依舊可用。

spring新配置方式:scope=“<作用域類型>”

<bean id="accountservice" class="com.foo.defaultaccountservice" scope="singleton"/>

除以上5種,spring還允許使用者自定義bean的作用域。org.springframework.beans.factory.config.scope接口定義新作用域,再通過org。springframework.beans.factory.config.customscopeconfigurer這個beanfactorypostprocessor注冊自定義的bean作用域。【很少需要使用者自定義作用域,自帶的足以滿足大部分需求】

2.3.5 基于注解的配置

1)使用注解定義bean

基于xml的配置,bean定義資訊和bean實作類本身分離;

基于注解的配置,bean定義資訊通過在bean實作類上标注注解實作。

@component("userdao")

    public class userdao{……}

等價于一下xml配置:

<bean id="userdao" class="com.smart.userdao"/>

除@component外,spring還提供3個功能基本和其等效的注解,也稱為bean的衍型注解。

@repository:标注dao實作類

@service:标注service實作類

@controller:标注web層的controller實作類衍型注解讓注解本身用途清晰化,也被spring賦予了一些特殊的功能。【推薦使用】

2)使用注解配置資訊啟動spring容器spring2.5後提供了context命名空間,提供了提供掃描包以應用注解定義bean的方式。

使用方式:

a、聲明context命名空間,xmlns:context="http://www.springframework.org/schema/context"

b、掃描類包以應用注解定義的bean,<context:component-scanbase-package="com.smart.anno">

context的命名空間的component-scan的base-package屬性指定一個需要掃描的基類包,spring将掃描此基類包的所有類,并從注解資訊中擷取bean資訊。

c、resource-pattern:過濾出特定類,僅掃描特定類而非基類包下的所有類。

<context:component-scanbase-package="com.smart" resource-pattern="anno/*.class">

resource-pattern屬性預設值為“**/*.class”,即基類包裡的所有類。此處設定為"anno/*.class",spring僅會掃描基類包anno子包中的類。

d、<context:component-scan>過濾子元素,如僅過濾基類包中實作了xxxservice接口的類或标注了某個特定注解的類等,而resource-pattern僅可按資源名稱過濾。

<context:include-filter>表示要包含的類,<context:exclude-filter>表示要排除的類;一個component-scan下可包含若幹個exclude和include。且這兩個過濾元素均支援多種類型的過濾表達式。

過濾類型中,除custom外,aspectj過濾表達能力最強,可輕易實作其他類型所表達的過濾規則。

2.3 Bean裝配

3)自動裝配bean【@autowired】

private userdao userdao;

}

@autowired:預設按類型比對,當有且僅有一個比對的bean時,spring将其注入@autowired标注的變量中。

①@autowired的requried屬性

若容器中沒有和按标注類型比對的bean,spring将抛出nosuchbeandefinitionexception異常,如果希望即使找不到比對的bean也不要抛出異常,可使用@autowired(required = false)進行标注。【required預設值為true】

②@qualifier指定注入bean的名稱

如果有超過一個比對的bean,可通過@qualifier注解限定bean的名稱。

@autowired

@qualifier("userdao") //①

假設容器有兩個類型userdao的bean,一個名為userdao,一個名為userdao2,則①處會注入名為userdao的bean。

③标注類方法

@autowired 可标注類成員變量及方法的入參,亦可标注類。

@autowired //自動将logdao傳給方法入參

public void setlogdao(logdao logdao) {

    this.logdao = logdao;

@autowired // 自動将,名為userdao的bean傳給方法入參

@qualifier("userdao")

public void setuserdao(userdao userdao) {

    this.userdao = userdao;

如果一個方法擁有多個入參,預設情況下,spring自動選擇比對入參類型的bean進行注入,spring允許使用@qualifier指定注入入參的bean的名稱。

public void init(@qualifier("userdao")userdao userdao,logdao logdao){

     this.userdao = userdao;

     this.logdao =logdao;

以上例子,userdao的入參注入名為userdao的bean,而logdao的入參注入logdao類型的bean。

note:

通常,spring容器的大部分bean是單執行個體,so無需通過@repository、@service等注解的value屬性指定名稱,也無需使用@qualifier按名稱注入。

④标注集合類

此處,plugin為接口,有兩個實作類且兩個實作類都通過@component标注為bean,so spring會将這兩個bean都注入plugins。

2.3.6 基于java類的配置

1)使用java類提供bean定義資訊

@configuration// 此注解說明此類可用于為spring提供bean的定義資訊

public class appconf {

    @bean // 将一個pojo标注為定義bean的配置類

    public userdao userdao() {

        return new userdao();

    }

    @bean // bean類型由方法傳回值類型決定,名稱預設和方法名相同,亦可顯示指定。

    public logdao logdao() {

        return new logdao();

    @bean(name="logonservice")

    public logonservice logonservice() {

        logonservice logonservice = new logonservice();

        logonservice.setlogdao(logdao()); // 注入上面定義的bean

        logonservice.setuserdao(userdao());

        return logonservice;

以上配置等價于

<bean id="userdao" class="com.smart.anno.userdao"/>

<bean id="logdao" class="com.smart.anno.logdao"/>

<bean id="logonservice" class="com.smart.conf.logonservice"

     p:logdao-ref="userdao" p:userdao-ref="logdao"/>

對比:

基于java類的配置方式:更靈活地實作bean的執行個體化及bean之間的裝配;

xml或基于注解: 通過配置聲明,靈活性略遜,但配置更簡單。

@configuration

public class daoconfig {

    @bean

    public userdao userdao(){

    @scope("prototype")

    public logdao logdao(){

------------------------

public class serviceconfig {

    @autowired

    private daoconfig daoconfig;

        system.out.println(daoconfig.logdao() == daoconfig.logdao());

        logonservice.setlogdao(daoconfig.logdao()); //a、像普通bean一樣調用其他bean方法

        logonservice.setuserdao(daoconfig.userdao());

@configuration注解類本身相當于标注了@component,即可像普通bean一樣被注入其他bean中(可直接調用@configuration中标注@bean的方法,如上)。

spring對配置類所有标注@bean的方法進行aop增強,将對聲明周期的邏輯植入進來。

a處調用daoconfig.logdao()邏輯:從spring容器傳回相應bean的單例,即多次調用daoconfig.logdao()傳回的都是相同bean。bean若标注@scope("prototype"),則每次傳回新的bean。

2)直接通過@configuration類啟動spring容器

// 使用@configuration類中提供的bean定義資訊啟動spring容器

applicationcontext ctx = new annotationconfigapplicationcontext(appconf.class); //直接傳入@configuration标注的java類

logonservice logonservice = ctx.getbean(logonservice.class);

注:

annotationconfigapplicationcontext支援加載多個配置類

//2.通過編碼方式注冊配置類

annotationconfigapplicationcontext ctx2 = new annotationconfigapplicationcontext();

ctx2.register(daoconfig.class);

ctx2.register(serviceconfig.class);

ctx2.refresh(); //重新整理容器以應用這些注冊的配置類

 //3.@import将多個配置類組裝到一個配置類中,僅需注冊這個組裝好的配置類即可啟動容器。

@import(daoconfig.class)

3)xml配置檔案引用@configuration的配置

// 通過上下文掃描加載到appconf的配置類

<context:component-scan base-package="com.smart.conf"

        resource-pattern="appconf.class" />

4)通過configuration配置類引用xml配置資訊

beans3.xml:

<bean id="userdao" class="com.smart.conf.userdao"/>

2.3.7 基于xml、注解、java類三種配置方式的比較

2.3 Bean裝配
2.3 Bean裝配

通常基于java類的方式使用較少。