1. 程式人生 > 其它 >跟著柴毛毛學Spring(2)——Bean的配置

跟著柴毛毛學Spring(2)——Bean的配置

Java中建立一個物件分兩步: 1.通過關鍵字new建立一個物件 2.通過建構函式或setter函式為物件新增初始化引數 當Spring出現後,物件的建立、成員變數的初始化、物件的銷燬均由Spring完成。 那麼,要讓Spring幫助我們建立物件,我們首先需要將要建立的物件的型別、初始化的值告訴Spring,然後Spring會在程式啟動的時候根據我們的要求建立物件。我們通過配置檔案來告訴Spring要建立哪些物件,並告訴Spring如何建立這些物件。

宣告一個Bean

在Spring中,讓Spring建立的物件叫做Bean,每一個bean都有成員函式和成員變數,如果bean的某些成員變數需要初始值,那麼在bean的配置檔案中宣告即可,否則Spring會給bean的成員們賦上預設的初始值。 如果已經有一個Person類,含有id和name兩個屬性:

class Person{
    private long id;
    private String name;

    public void setId(long id){
        this.id = id;
    }
    public long getId(){
        return this.id;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}

然後我們需要建立一個Spring的配置檔案,在裡面作如下定義:

<?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-4.5.xsd">  

    <bean id="person" class="com.njupt.Person"></bean>

</beans>

Spring的配置檔案由beans標籤開始,beans標籤下的bean標籤內即可宣告一個bean。 - id表示這個bean的名字,可以自定義,當我們需要使用這個物件時,通過這個id來獲取物件。 - class表示這個類的完整路徑。Spring通過class屬性找到這個類。 到此為止,Person類的配置已經完成。當程式啟動的時候,Spring會讀取這個配置檔案,根據class找到每個bean對應的類,並初始化它們。 當我們需要使用一個物件時,通過如下操作即可獲得:

ApplicationContext context = new ClassPathXmlApplicationContext("xml的路徑");
Person person = (Person)context.getBean(“bean的名字”)

給Bean注入初始值

在上述示例中,Spring建立了一個Person物件,由於未指定初始值,因此Spring為person物件的屬性賦上了預設值。下面我們來介紹如何讓Spring為一個物件賦上指定的初始值。 在Java中,給一個物件賦上初始值的方法有兩種: 1. 通過建構函式將初始值傳遞給物件 2. 在建立完物件後通過set函式為物件賦上初始值

Spring也採用了這兩種方式,分別叫做:構造器注入和屬性注入。

構造器注入

1.注入基本型別的值 我們首先為Person類新增一個建構函式:

class Person{
    private long id;
    private String name;

    public Person(String name,long id){
        this.name = name;
        this.id = id;
    }

    public void setId(long id){
        this.id = id;
    }
    public long getId(){
        return this.id;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}

然後在bean標籤中新增屬性:

<bean id="person" class="com.njupt.Person">
        <constructor-arg value="柴毛毛"/>
        <constructor-arg value="1"/>
</bean>

關於constructor-arg有如下注意點: - 屬性constructor-arg的次序需要和建構函式中引數的順序一致。 - value表示屬性值。 - 屬性constructor-arg中,無需指定屬性名,只需填寫屬性值。 - 屬性constructor-arg中,所有的屬性值均是String型別,Spring會在賦值的時候自動進行型別轉換。

2.注入物件引用 假設Person類中有一個Father型別的屬性,並且新增引數為Father的建構函式:

class Person{
    private long id;
    private String name;
    private Father father;

    public Person(Father father){
        this.father = father;
    }
    ……省略所有setter、getter函式……
}

此時,建構函式的引數是一個引用型別的變數,我們可以做如下處理:

    <!-- 首先建立Father型別的bean -->
    <bean id="father" class="com.njupt.Father">
        <constructor-arg value="柴毛毛的爸爸"/>
        <constructor-arg value="1"/>
    </bean>

    <!-- 通過ref引用father物件 -->
    <bean id="person" class="com.njupt.Person">
        <constructor-arg ref="father"/>
    </bean>

3.通過工廠建立bean 如果一個類是工廠類,它沒有建構函式,因此我們沒有辦法通過構造器來初始化這個物件。但工廠模式會提供給我們一個靜態函式,用來獲取工廠物件,那麼在配置bean的時候做如下操作:

    <bean id="person" class="com.njupt.Person" factory-method="getIntance"/>

對於工廠類,我們需要呼叫getInstance來獲取工廠物件,因此在配置bean的時候,我們需要通過factory-method屬性告訴Spring,獲取這個工廠物件的函式是getInstance。

屬性注入

通過上面我們瞭解到,Spring通過bean標籤下的constructor-arg標籤為建構函式注入引數值,接下來介紹Spring通過property標籤為成員變數注入初始值。

1.注入基本型別的值 為Person物件的name屬性注入一個初始值“chaiMaoMao”: - name:屬性名 - value:屬性值

    <bean id="person" class="com.njupt.Person">
        <property name="name" value="chaiMaoMao"/>
    </bean>

注意:在編寫配置檔案的時候,Spring中value的全是String型別,但Spring會在執行的時候自動將其轉換為相應的型別。

2.注入物件引用 在bean中通過ref屬性注入一個引用型別的變數。如:Person類中有一個Father型別的屬性father,如果我們需要將一個father物件注入Person的father屬性中,需要進行如下操作:

    <!-- 引用name為father的bean注入給Person的father屬性 -->
    <bean id="person" class="com.njupt.Person">
        <property name="father" ref="father"/>
    </bean>

    <!-- 定義name為father的bean -->
    <bean id="father" class="com.njupt.Father">
        <constructor-arg value="柴毛毛的爸爸"/>
        <constructor-arg value="1"/>
    </bean>

3.注入內部bean 如果一個bean僅供某一個bean使用,那麼可以將這個bean宣告為內部bean。如:name為father的bean只允許注入給name為person的bean,那麼就將father這個bean以放在person的內部,如下所示:

    <bean id="person" class="com.njupt.Person">
        <property name="father">
            <bean class="com.njupt.Father" />
        </property>
    </bean>

注意: 1. 內部bean沒有名字,只適應於一次性注入,不能被其他bean引用。 2. 注入內部bean不僅限於屬性注入,也可用於構造器注入,如下所示:

    <bean id="person" class="com.njupt.Person" init-method="createInstance" destory-method="destoryInstance">
        <constructor-arg>
            <bean class="com.njupt.Father" />
        </constructor-arg>  
    </bean>

Bean的作用域

在Spring中,預設情況下bean都是單例。也就是說,當我們向Spring請求一個bean物件時,Spring總給我們返回同一個bean物件。 **注意:**Spring 中所說的“單例”與Java中的單例稍有不同。Spring中的單例是指:在同一個ApplicationContext中相同名字的bean物件是同一個;而Java中的單例是指:整個JVM中單例的物件只有一個。 當然,我們可以通過改變bean標籤的scope引數來設定bean的作用域。常用的scope對應的值有: - singleton:在同一個Spring Context中,一個bean只有一個例項物件。(預設) - prototype:每次向Spring請求一個bean物件,Spring都會建立一個新的例項。

初始化和銷燬Bean

如果需要在bean物件初始化之後或銷燬之前做一些額外的操作的話,可以作如下配置: 1. 首先需要在bean中定義函式,供Spring建立該類物件或銷燬該物件的時候呼叫:

    public void createInstance(){
        System.out.println("物件被建立啦!");
    }

    public void destoryInstance(){
        System.out.println("物件被銷燬啦!");
    }
  1. 在XML中作如下配置: 告訴Spring,這個bean在被建立的時候呼叫這個類中哪個函式,這個類被銷燬的時候呼叫這個類中的哪個函式。
<bean id="person" class="com.njupt.Person" init-method="createInstance" destory-method="destoryInstance">
        <constructor-arg ref="father"/>
</bean>

如果所有的bean在初始化或銷燬的時候都需要呼叫函式,那麼可以在beans標籤中設定一個全域性的引數:default-init-method和default-destroy-method。這樣,這個beans標籤下的所有bean在建立或銷燬時都會呼叫createInstance()和destoryInstance()。

<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-4.5.xsd"

    default-init-method="createInstance" 
    default-destory-method="destoryInstance">  

</beans>

裝配集合

到此為止,不管是裝配基本型別還是裝配物件的引用,都是在裝配單個屬性,那麼該如果裝配一個集合呢?

集合元素

用途

list

用於裝配單值集合,允許重複

set

用於裝配單值集合,不允許重複

map

用於裝配鍵值對集合,key和value可以為任意型別

props

用於裝配鍵值對集合,key和value只能為String型別

- 對於單個值的集合,如陣列、List、Set,均可以用list標籤來裝配,list標籤和set標籤的不同之處僅僅是前者允許重複,而後者不允許重複。 - 對於鍵值對集合,可以使用set標籤或props標籤,兩者的區別是:前者的key和value可以是任何型別,而後者的key和value只能是String型別。

1.裝配List:

    <bean id="person" class="com.njupt.Person">
        <property name="list">
            <list>
                <ref bean="a"/>
                <ref bean="b"/>
                <ref bean="c"/>
            </list>
        </property>
    </bean>

2.裝配Map:

    <bean id="person" class="com.njupt.Person">
        <property name="map">
            <map>
                <entry key="key_a" value-ref="a"/>
                <entry key="key_b" value-ref="b"/>
                <entry key="key_c" value-ref="c"/>
            </map>
        </property>
    </bean>

3.裝配props:

    <bean id="person" class="com.njupt.Person">
        <property name="map">
            <props>
                <prop key="key_a">value_a</prop>
                <prop key="key_b">value_b</prop>
                <prop key="key_c">value_c</prop>
            </props>
        </property>
    </bean>

SpEL表示式

SpEL=Spring Express Language 這種表示式用在Spring的配置檔案中,可以直接獲取某個bean的某一個屬性值或獲得一個函式的執行結果,相當屌! SpEL表示式不難,下面舉幾個例子相信聰明的你就能理解了。

  • 引用一個bean的屬性值
    <bean id="person" class="com.njupt.Person">
        <property name="name" value="#{father.name}" />
    </bean>
  • 引用一個bean的函式的執行結果
    <bean id="person" class="com.njupt.Person">
        <property name="name" value="#{father.getName()}" />
    </bean>
  • 引用Java中某個靜態函式的執行結果
    <bean id="person" class="com.njupt.Person">
        <property name="name" value="#{T(java.lang.Math).random()}" />
    </bean>
  • 數值運算
    <bean id="person" class="com.njupt.Person">
        <property name="id" value="#{count.id + 100}" />
    </bean>
  • 字元連線
    <bean id="person" class="com.njupt.Person">
        <property name="name" value="#{father.name +' '+ mother.name}" />
    </bean>
  • 比較運算
    <bean id="person" class="com.njupt.Person">
        <property name="equal" value="#{father.name == mother.name}" />
    </bean>
  • 訪問集合成員
    <bean id="person" class="com.njupt.Person">
        <property name="name" value="#{list['chaiMaoMao']}" />
    </bean>
    <bean id="person" class="com.njupt.Person">
        <property name="name" value="#{list[2]}" />
    </bean>
  • 查詢集合成員
    <bean id="person" class="com.njupt.Person">
        <property name="name" value="#{list.?[age gt 20]}" />
    </bean>
  • 投影集合
    <bean id="person" class="com.njupt.Person">
        <property name="names" value="#{list.![name]}" />
    </bean>