Spring的核心機制:依賴注入(xml方式)


 依賴注入的概念

如果要在一個類中,使用另一個類,傳統的方式是直接new:

class  A{

  //......

  B  b=new B();

  //......

}

A類對象依賴於B類對象,如果沒有B類對象,A類對象就不能正常工作,稱為A依賴B。

上面的方式會增加A類與B類的耦合,不利於項目后期的升級(擴展)、維護。

 

 

在Spring中,B類的實例(被調用者),不再由A類(調用者)創建,而是由Spring容器創建,創建好以后,由Spring容器將B類實例注入A類實例中,稱為依賴注入(Dependency Injection,DI)。

原本是由A類主動創建B類對象(A類控制B類的創建),現在是Spring容器創建B類對象,注入A類對象中,A類被動接受Spring容器創建的B類實例,B類對象創建的控制權發生了反轉,所以又叫做控制反轉(Inversion of Control,IoC)。

控制反轉(IoC)是由依賴注入(DI)實現的,依賴注入又是由spring容器實現的,所以Spring容器又叫做Spring  IoC容器。。

 

 

依賴注入是一種優秀的解耦方式,由Spring容器負責控制類(Bean)之間的關系,降低了類之間的耦合。

常用的方式有2種:

  • 設值注入,也叫set方式注入
  • 構造方法注入

 

 


 

 

設值注入

將依賴作為成員變量,通過主調類的setter方法注入依賴。

public class A {
    private B b;

    public void setB(B b) {
        this.b = b;
    }
    
    //......
}

 

 

xml配置:

    <bean name="b" class="com.chy.bean.B" />
    <bean name="a" class="com.chy.bean.A">
        <property name="b" ref="b"/>
    </bean>

使用<property>注入依賴,name指定屬性名(成員變量名),ref指定要注入的bean(value指定要注入的常量值)。

如果要注入多個依賴,使用多個<property />即可。

 

 


 

 

構造方法注入

將依賴作為成員變量,通過主調類的構造方法注入依賴。

public class A {
    private B b;

    public A(B b) {
        this.b = b;
    }

    //......
}

 

 

xml配置:

<bean name="b" class="com.chy.bean.B" />
<bean name="a" class="com.chy.bean.A">
        <constructor-arg name="b" ref="b" />
</bean>

一個<constructor-arg />注入一個參數,name指定構造方法中的形參名,ref指定要注入的bean(value指定要注入的常量值)。

形參可用 name="形參名" 指定,也可以使用 index="形參表下標" 來指定(第一個參數 => 下標0)。

如果有多個形參,使用多個<constructor-arg />即可,spring會調用對應的構造方法。

 

 


 

不管是設值注入,還是構造方法注入,都是將依賴作為成員變量,所以有時候也把注入依賴叫做注入屬性。

 


 

  

依賴可分為3種類型:

  • 注入int、float、String之類的基本數據類型,使用value。

比如根據學號查學生信息,需要注入一個int型的學號。

spring會自動將值轉換為需要的類型,比如需要的String,value="chy"會以String的形式注入。value="1",如果需要的是int,就轉換為int注入,如果需要的是String,就轉換為String注入。

 

  • 注入其他Bean的實例,使用ref。

 

  • 注入數組、集合、Properties等復雜類型

 

 


 

 

注入復雜類型的依賴

將復雜類型的數據數據作為成員變量:

    private Object[] arr;
    private List<Object> list;
    private Set<Object> set;
    private Map<String,Object> map;
    private Properties properties;

設值注入需提供對應的setter方法,構造方法注入需提供對應的構造方法。

 

 

設值注入:

 <bean name="a" class="com.chy.bean.A">
        <!-- 注入數組-->
        <property name="arr">
            <array>
                <!-- 基本數據類型使用value,bean的實例使用ref,可嵌套其他復雜類型-->
                <value>chy</value>
                <ref bean="b" />
            </array>
        </property>

        <!-- 注入List -->
        <property name="list">
            <list>
                <value>chy</value>
                <ref bean="b" />
            </list>
        </property>

        <!-- 注入Set -->
        <property name="set">
            <set>
                <value>chy</value>
                <ref bean="b" />
            </set>
        </property>

        <!-- 注入Map-->
        <property name="map">
            <map>
                <!-- Map的key只能是String,基本數據類型用value,其他Bean的實例用value-ref  -->
                <entry key="id" value="1" />
                <entry key="user" value-ref="b" />
            </map>
        </property>

        <!-- 注入Properties -->
        <property name="properties">
            <props>
                <!-- 鍵、值都只能是String -->
                <prop key="username">chy</prop>
                <prop key="password">abcd</prop>
            </props>
        </property>
</bean>

<property name="">  name指定屬性名(成員變量名)。

數組、List、Set的配置方式是差不多的。

 

 

構造方法注入:

<constructor-arg name="arr">
            <array>
                <value>chy</value>
                <ref bean="b" />
            </array>
</constructor-arg>

配置方式和設值注入差不多,只不過將 property 換為 constructor-arg ,name是指定形參名。

 

用的最多的是設值注入,因為很多時候都要修改成員變量的值,setter方法一般都要寫,直接用setter方法設值注入,沒必要再寫帶參的構造方法。

 

 


 

 

使用自動裝配注入其它Bean的實例

原先注入其它bean的實例,需要使用<property />或<constructor />注入。

使用自動裝配后,不需要使用<property />、<constructor />,spring會自動在容器中找到滿足要求的其它bean,注入進來。

 

 

<bean name="a" class="com.chy.bean.A" autowire="byName" />

可選的值:

  • no   默認值,不使用自動裝配,如果要注入其它bean的實例,需要使用<property />或<constructor />。
  • byName   根據name來自動裝配
  • byType  根據type來自動裝配
  • constructor  根據構造函數形參類型進行byType方式的自動裝配
  • default   使用全局默認的自動裝配方式。

byName和byType都能在設值注入中使用,constructor只能在構造方法注入中使用。

 

 

byName

public class A {
    private B b;

    public void setB(B b) {
        this.b = b;
    }
}
<bean name="b" class="com.chy.bean.B" />
<bean name="a" class="com.chy.bean.A" autowire="byName" />

A依賴B,A中有對應的setter方法。

byName,name就是setter方法的方法名,去掉set,后面部分使用camel寫法,比如setB() =>  b,

spring會自動到容器中找到name="b"的bean,注入。

name="b"的bean只能有一個,不然spring不知道要注入哪個。

 

 

byType

和byName差不多,也是要配合setter方法使用。不同的是:

byType,type是形參表的參數類型。比如setB(B  b),參數類型是B,Spring自動找到class=“B”的bean,注入。

class=“B”的bean只能有一個,不然spring不知道要注入哪個。

 

 

constructor 

public class A {
    private B b;

    public A(B b) {
        this.b = b; }
}

顧名思議,需要和構造方法注入搭配使用

找到帶參的構造器,根據參數類型,按照byType的方式注入依賴

 

 

default   

使用全局默認的自動裝配方式。

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

    <bean name="b" class="com.chy.bean.B" />
    <bean name="a" class="com.chy.bean.A" autowire="default" />
</beans>

需要在根元素<beans>中設置全局默認的自動裝配方式,所有default方式的自動裝配都是使用 default-autowire 設置的方式進行裝配。

 

 

自動裝配的貪婪原則

自動裝配會盡量多地注入依賴。

比如constructor ,有2個構造方法:(B b)、(B b, C c),如果容器中有B、C的實例,則優先調用(B b, C c),會盡量多地注入依賴。

 

 

自動裝配的優點:一個屬性就搞定,不必寫大量的<property />或<constructor />。

缺點:自動裝配只能注入其它bean的實例,使用時有限制條件。(可以和注入基本類型、復雜類型的方式一起使用。實際上,注入基本類型、bean的實例、復雜類型都可以搭配使用。)

 

 


 

 

使用SpEL注入依賴

SpEL,即Spring Expression Language,spring表達式語言。

使用SpEL可以注入基本類型,可以注入其它Bean,可以訪問其它Bean的成員變量、調用其它Bean中的方法。

 

使用示例:

    <bean name="score" class="com.chy.bean.Score">
        <property name="chinese" value="#{90}" />
        <property name="math" value="#{100}" />
        <property name="english" value="#{95}" />
    </bean>
    <bean name="student" class="com.chy.bean.Student">
        <property name="no" value="#{1}" />
        <property name="name" value="#{'chy'}" />
        <property name="score" value="#{score}" />
    </bean>

SpEL放在#{ }中,數值型直接寫,字符、字符串要加單引號,可以直接引用其它Bean。

SpEL使用的是設值注入,所以需要提供setter方法,只能用<property />注入值,不能使用構造方法注入。

不管值是什么類型,都只能用value,不能用ref。

 

可以直接訪問其它Bean的成員變量,比如 #{score.math} ,實質是調用對應的getter方法,所以需要提供getter方法。

可以調用其它Bean的方法,比如 #{score.getMath()},如果該方法返回void,作為null處理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM