1. 程式人生 > >4.1 Spring beans的建立和配置(XML方式)

4.1 Spring beans的建立和配置(XML方式)

準備


//--Classes.java
package com.erick.d1.hello;

public class Classes {
    private String name;
    private int number;

    public Classes() { }

    public Classes(String name, int number) {
        super();
        this.name = name;
        this.number = number;
    }

    @Override
    public
String toString() { return "Classes [name=" + name + ", number=" + number + "]"; } //getter and setter //... } //--Student.java package com.erick.d1.hello; public class Student { private int age; private String name; //愛好 private List<String> hobby; private
Classes classes; //getter and setter //... }

1. 建立bean

spring支援使用 構造器、靜態工廠、例項工廠 三種方式來建立bean

構造器建立bean

構造器建立bean是比較常見的,如果不採用構造注入,Spring會呼叫bean的午餐構造器來建立例項,
所以該Bean必須提供無參的構造器,使用這種方式配置時,class屬性是必須的。

下面的配置(classes)使用了構造器建立,並且採用了構造注入方式


<!-- Beans.xml -->

<bean id="student" class
="com.erick.d1.hello.Student">
<property name="name" value="tom" /> <property name="age" value="12" /> <property name="classes" ref="classes"/> </bean> <bean id="classes" class="com.erick.d1.hello.Classes"> <!-- 構造器注入 --> <constructor-arg type = "String" name="name"> <value>正音班1</value> </constructor-arg> <constructor-arg name="number"> <value>20</value> </constructor-arg> </bean>

靜態/例項工廠方法建立bean

後面會單獨介紹使用工廠方法建立Bean

2. 配置Bean

使用內部bean

<bean id="student" class="com.erick.d1.hello.Student">
    <property name="name" value="tom" />
    <property name="age" value="12" />
    <property name="classes">
        <!-- 內部bean不能被其他bean引用 -->
        <bean class="com.erick.d1.hello.Classes">
            <property name="name" value="08級一班"/>
            <property name="number" value="31" />
        </bean>
    </property>
</bean>

級聯屬性配置

<bean id="student" class="com.erick.d1.hello.Student">
    <property name="name" value="tom" />
    <property name="age" value="12" />

    <!-- 必須先有一個班級物件才能級聯賦值,否則報錯 -->
    <property name="classes" ref="classes"/>
    <property name="classes.name" value = "08級一班" />
    <property name="classes.number" value="31" />
</bean>

配置集合屬性


<!-- List集合 -->
<property name="hobby">
    <list>
        <value>網球</value>
        <value>網遊</value>
    </list>
</property>

<!-- Map集合 -->
<property name="hobby">
    <map>
        <entry key="" value="" />
        <entry key="" value="" />
    </map>
</property>

<!-- propertie 配置 -->
<bean id = "dataSource" class="">
    <property name="properties">
        <props>
            <prop key="user">root</prop>
            <prop key="password">123</prop>
        </props>
    </property>
</bean>

集合配置時需要在<property>元素內。若想配置公用的需要新增util名稱空間


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<bean id="student" class="com.erick.d1.hello.Student">
    <property name="name" value="tom" />
    <property name="age" value="12" />

    <property name="hobby" ref="hobby" />
</bean>

<util:list id="hobby">
    <value>網球</value>
    <value>網遊</value>
</util:list>

自動裝配

使用autowire屬性進行自動裝配,自動裝配有三種方式:

  1. byName 通過屬性名裝配,屬性名必須完全匹配才能注入。
  2. byType 通過型別裝配,注入的型別若容器中有兩個bean則注入失敗。
  3. 構造器注入,比較複雜,不推薦使用。

<bean id="student" class="com.erick.d1.hello.Student" autowire="byType">
    <property name="name" value="tom" />
    <property name="age" value="12" />
</bean>

<bean id="classes" class="com.erick.d1.hello.Classes">
    <constructor-arg type="String" name="name">
        <value>正音班1</value>
    </constructor-arg>
    <constructor-arg name="number">
        <value>20</value>
    </constructor-arg>
</bean>

bean配置繼承


<bean id="studentAbs" abstract="true" class="com.erick.d1.hello.Student">
    <property name="name" value="cat"/>
    <property name="age" value="99"/>
</bean>

<bean id="student"  autowire="byType" parent="studentAbs">
    <property name="age" value="12" />
</bean>
  • 繼承的是配置!類似模板,而非真正的父子關係。
  • 子bean可以覆蓋從父bean中繼承的配置
  • 父bean可以作為配置模板,也可以作為Bean例項。abstract屬性設定為true,這樣spring容器不會例項化這個bean。
  • 可以繼承的配置包括bean的屬性配置,但不是所有的屬性都會被繼承,比如autowire abstract等。
  • 當父bean屬性配置為abstract=trueclass屬性可以不指定,讓子bean指定。

依賴bean配置

<bean id="student" class="com.erick.d1.hello.Student" depends-on="classes">
    <property name="name" value="tom" />
    <property name="age" value="12" />
</bean>

若bean A 依賴於 bean B ,向容器請求bean A時,容器會先建立bean A,發現需要bean B注入,再建立bean B,並將其注入,然後將bean A返回。若指定depends-on則先建立bean B後建立bean A。

  • Spring允許使用者通過depends-on屬性設定bean的前置依賴的bean,前置依賴的bean會在本bean例項化之前建立。
  • 若前置依賴於多個bean,則可以通過逗號、空格的方式指定多個bean。

bean的別名

由於XML規範規定了id屬性必須由字母和數字組成,且只能以字母開頭,但在某些特殊情況下,例如與struts1整合時,必須為某些bean指定特殊標識名,測試就必須為其指定別名。

定義別名兩種方式:

  • 設定<bean/>的屬性name,若需要指定多個別名則可以在name中使用 逗號、冒號或者空格來分隔。通過任何一個別名都可以訪問該bean例項。
  • 通過<alias/>元素為已有的bean指定別名。

<!-- 為person bean指定三個別名 -->
<bean id="person" class="..." name="#abc,@123,abc*"/>

<!-- 為已有的person bean指指定別名 -->
<alias name="person" alias="jack"/>
<alias name="person" alias="jackee"/>

bean的作用域

使用scop屬性來配置bean的作用域。

  • singleton:單例的,整個容器的生命週期內只建立一次該bean。預設情況是單例的。單例情況預設是非懶載入,即容器啟動時建立該bean。可以指定lazy-init=true改為懶載入。

  • prototype:原型的,每次用到該bean時,容器都會建立一個新的bean。該模式載入模式為懶載入,並且修改lazy-init=false不會起任何作用。

  • request:對於一次http請求,request作用域的bean將只生成一個例項。這意味著在同一次http請求內,每次請求該bean,得到的總是同一個例項。只有在Web應用中使用Spring時該作用域才真正有效。

  • session:對於一次http會話,session作用域的bean只生成一個例項,只有在Web應用中使用Spring時該作用域才真正有效。

  • global session:每個全域性的http session 對應一個bean例項,在典型的情況下,僅在使用portlet context的時候有效。只有在Web應用中使用Spring時該作用域才真正有效。

預設情況為singleton.

為使request 和 session 作用域生效,必須將http請求物件繫結到為該請求提供服務的執行緒上,這使具有request 或 session作用域的bean例項能夠在後面的呼叫鏈中被訪問到。需要在web.xml中增加下面Listener配置,該Listener負責使request作用域生效。

<listener>
    <listener-class>
        org.springframework.web.context.request.RequestContextListener
    </listener-class>
</listener>

若web應用直接使用spring MVC作為MVC框架,即用SpringDispatcherServletDispatcherPortlet 來攔截使用者請求,則無需這些額外配置,因為SpringDispatcherServletDispatcherPortlet已經處理了所有和請求有關的狀態處理。