1. 程式人生 > >Spring Bean 配置細節

Spring Bean 配置細節

引用其它 Bean

組成應用程式的 Bean 經常需要相互協作以完成應用程式的功能. 使 Bean 能夠相互訪問, 就必須在 Bean 配置檔案中指定對 Bean 的引用

Bean 的配置檔案中, 可以通過 <ref> 元素或 ref  屬性Bean 的屬性或構造器引數指定對 Bean 的引用.

如我們構造一個Person類

public class Person {

    private String name;
    private int age;

    private Car car;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}

在bean中通過ref建立bean之間的聯絡

<bean id="person" class="com.spring.Person">
    <property name="name" value="Tom"></property>
    <property name="age" value="24"></property>
    <!--可以使用property 的ref 屬性建立bean之間的引用關係-->
    <property name="car" ref="car2"></property>
</bean>
Person person = (Person) ctx.getBean("person");
System.out.println(person);

呼叫該bean可以看到程式輸出

Person{name='Tom', age=24, car=Car{brand='Baoma', corp='Tianjin', price=0.0, maxSpeed=200}}

也可以在屬性或構造器裡包含 Bean 的宣告, 這樣的 Bean 稱為內部 Bean

<bean id="person" class="com.spring.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="24"></property>

        <!--可以使用property 的ref 屬性建立bean之間的引用關係-->
        <!--<property name="car" ref="car2"></property>-->

        <!--使用內部bean-->
        <property name="car">
            <bean class="com.spring.Car">
                <constructor-arg value="Ford"></constructor-arg>
                <constructor-arg value="Changan"></constructor-arg>
                <constructor-arg value="200000"></constructor-arg>
            </bean>
        </property>

    </bean>

內部bean不能被外部引用,只能在內部使用

Bean 例項僅僅給一個特定的屬性使用時, 可以將其宣告為內部 Bean. 內部 Bean 宣告直接包含在 <property> <constructor-arg> 元素裡, 不需要設定任何 id name 屬性

內部 Bean 不能使用在任何其他地方

注入引數詳解null 值和級聯屬性

可以使用專用的 <null/> 元素標籤為 Bean 的字串或其它物件型別的屬性注入 null

StrutsHiberante 等框架一樣,Spring 支援級聯屬性的配置

<bean id="person2" class="com.spring.Person">
        <constructor-arg value="Jerry"></constructor-arg>
        <constructor-arg value="25"></constructor-arg>
        <!--<constructor-arg ref="car"></constructor-arg>-->
        <!--測試賦值null-->
        <constructor-arg><null></null></constructor-arg>
    </bean>

用該方法,此時給person2這個物件賦的car值為null

Person{name='Jerry', age=25, car=null}

集合屬性

假設一個person擁有兩輛車,我們現在構造一個Person類,其屬性Car為list型別

package com.collection;

import java.util.List;

public class Person {

    private String name;
    private int age;

    private List<Car> cars;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Car> getCars() {
        return cars;
    }

    public void setCars(List<Car> cars) {
        this.cars = cars;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", cars=" + cars +
                '}';
    }
}

更改配置檔案

<!--測試如何配置集合屬性-->
    <bean id="person3" class="com.collection.Person">
        <property name="name" value="Mike"></property>
        <property name="age" value="23"></property>
        <property name="cars">
            <list>
                <!--cars是一個集合型別-->
                <ref bean="car"></ref>
                <ref bean="car2"></ref>
            </list>
        </property>
    </bean>

注意:其中ref指向的bean,其car和car2必須和Person在同一個包下

執行

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) ctx.getBean("person3");
System.out.println(person);

我們看看執行結果

Person{name='Mike', age=23, cars=[Car{brand='Audi', corp='ShangHai', price=300000.0, maxSpeed=0}, Car{brand='Baoma', corp='Tianjin', price=0.0, maxSpeed=200}]}

Spring可以通過一組內建的 xml 標籤(例如: <list>, <set> <map>) 來配置集合屬性.

配置 java.util.List 型別的屬性, 需要指定 <list>  標籤, 在標籤裡包含一些元素. 這些標籤可以通過 <value> 指定簡單的常量值, 通過 <ref> 指定對其他 Bean 的引用或者可以通過構造方法注入,具體的如何通過構造方法注入可參考上篇部落格. 通過<bean> 指定內建 Bean 定義. 通過 <null/> 指定空元素. 甚至可以內嵌其他集合.

陣列的定義和 List 一樣, 都使用 <list>

Java.util.Map

配置 java.util.Set 需要使用 <set> 標籤, 定義元素的方法與 List 一樣.

Java.util.Map 通過 <map> 標籤定義, <map> 標籤裡可以使用多個 <entry> 作為子標籤. 每個條目包含一個鍵和一個值.

必須在 <key> 標籤裡定義鍵

因為鍵和值的型別沒有限制, 所以可以自由地為它們指定 <value>, <ref>, <bean> <null> 元素.

可以將 Map 的鍵和值作為 <entry> 的屬性定義: 簡單常量使用 key value 來定義; Bean 引用通過 key-ref value-ref 屬性定義

package com.collection;


import java.util.Map;

public class NewPerson {

    private String name;
    private int age;

    private Map<String,Car> cars;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Map<String, Car> getCars() {
        return cars;
    }

    public void setCars(Map<String, Car> cars) {
        this.cars = cars;
    }

    @Override
    public String toString() {
        return "NewPerson{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", cars=" + cars +
                '}';
    }
}

我們再看看配置檔案,使用map節點及map的entry子節點配置Map型別的成員變數

<bean id="newPerson" class="com.collection.NewPerson">
        <property name="name" value="Rose"></property>
        <property name="age" value="28"></property>
        <property name="cars">
            <map>
                <entry key="AA" value-ref="car"></entry>
                <entry key="BB" value-ref="car2"></entry>
            </map>
        </property>
    </bean>

看執行結果

NewPerson{name='Rose', age=28, cars={AA=Car{brand='Audi', corp='ShangHai', price=300000.0, maxSpeed=0}, BB=Car{brand='Baoma', corp='Tianjin', price=0.0, maxSpeed=200}}}

使用 <props> 定義 java.util.Properties, 該標籤使用多個 <prop> 作為子標籤. 每個 <prop> 標籤必須定義 key 屬性.

定義一個NewPerson類,其Car型別使用Map型別

新建Properties類

import java.util.Properties;

public class DataSource {

    private Properties properties;

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "DataSource{" +
                "properties=" + properties +
                '}';
    }
}

配置,使用props和prop子節點為Properties屬性賦值

<!--配置Properties屬性值-->
    <bean id="dataSource" class="com.collection.DataSource">
        <property name="properties">
            <props>
                <prop key="user">root</prop>
                <prop key="password">1234</prop>
                <prop key="jdbcUrl">jdbc:mysql://test</prop>
                <prop key="driverClass">com.mysql.jdbc.Driver</prop>
            </props>
        </property>
    </bean>

執行結果

DataSource{properties={driverClass=com.mysql.jdbc.Driver, user=root, password=1234, jdbcUrl=jdbc:mysql://test}}

如何將集合的配置拿出來,希望它也配置成一個Bean的方式

使用 utility scheme 定義集合

使用基本的集合標籤定義集合時, 不能將集合作為獨立的 Bean 定義, 導致其他 Bean 無法引用該集合, 所以無法在不同 Bean 之間共享集合.

可以使用 util schema 裡的集合標籤定義獨立的集合 Bean. 需要注意的是, 必須在 <beans> 根元素裡新增 util schema 定義

如配置檔案寫成

<!--配置單例的集合bean,以供多個bean引用-->
    <util:list id="cars">
        <ref bean="car"></ref>
        <ref bean="car2"></ref>
    </util:list>
    <bean id="person4" class="com.collection.Person">
        <property name="name" value="Jack"></property>
        <property name="age" value="29"></property>
        <property name="cars" ref="cars"></property>
    </bean>

此時再執行結果如下

Person{name='Jack', age=29, cars=[Car{brand='Audi', corp='ShangHai', price=300000.0, maxSpeed=0}, Car{brand='Baoma', corp='Tianjin', price=0.0, maxSpeed=200}]}

使用 p 名稱空間

為了簡化 XML 檔案的配置,越來越多的 XML 檔案採用屬性而非子元素配置資訊。

Spring 2.5 版本開始引入了一個新的 p 名稱空間,可以通過 <bean> 元素屬性的方式配置 Bean 的屬性。

使用 p 名稱空間後,基於 XML 的配置方式將進一步簡化

 <!--通過p名稱空間為bean的屬性賦值,需先匯入p名稱空間,相對於傳統的配置方式更加簡潔-->
    <bean id="person5" class="com.collection.Person" p:age="30" p:name="Queen" p:cars-ref="cars"></bean>

執行結果

Person{name='Queen', age=30, cars=[Car{brand='Audi', corp='ShangHai', price=300000.0, maxSpeed=0}, Car{brand='Baoma', corp='Tianjin', price=0.0, maxSpeed=200}]}

注:該部落格主要說明了配置bean的一些細節,如果不明白可以先看看前面幾篇部落格