Spring的Core模塊


  Core模塊主要的功能是實現了反向控制IOC(Inversion of Control)與依賴注入DI(Dependency Injection)、Bean配置以及加載。Core模塊中有Beans、BeanFactory、BeanDefinitions、ApplicationContext等幾個重要概念。

  Beans為Spring里的各種對象,一般要配置在Spring配置文件中:BeanFactory為創建Beans的Factory,Spring通過BeanFactory加載各種Beans;BeanDefinition為Bean在配置文件中的定義,一般要定義id與class:ApplicationContext代表配置文件。

  這些類都位於org.springframework.beans和org.springframework.context中。這是Spring最核心的包。Core模塊依賴於Spring的Core類庫。

  BeanFactory工廠

  BeanFactory是實例化、配置、管理眾多Bean的容器。這些Bean類一般是離散的,但在Spring中被配置為相互依賴。BeanFactory根據配置實例化Bean對象,並設置相互的依賴性。

  BeanFactory可用接口org.springframework.beans.factory.BeanFactory表示。BeanFactory有多種實現,最常用的為org.springframework.beans.factory.xml.XmlBeanFactory。XmlBeanFactory能加載XML格式的配置文件。

  實例化BeanFactory

  在Web程序中用戶不需要實例化BeanFactory,Web程序加載的時候會自動實例化BeanFactory,並加載所有的Beans,將各種Bean設置到各個Servlet中、Struts的Action中、或者Hibernate資源中。開發者直接編寫Servlet、Action、Hibernate相關的代碼即可,無須操作 BeanFactory。

  在Java桌面程序中,需要從BeanFactory中獲取Bean,因此需要實例化BeanFactory,構造函數的參數為配置文件的路徑。例如加載ClassPath下的配置文件可以用ClassPathResource加載,然后傳遞給XmlBeanFactory構造函數。代碼如下:

ClassPathResource res = new ClassPathResource("applicationContext.xml"); // 獲取配置資源
XmlBeanFactory factory = new XmlBeanFactory(res); // 獲取對象工廠
IService hello = (IService)factory.getBean("service"); // 獲取對象
...// 其他代碼略
factory.destorySingletons(); // 銷毀對象

  參數applicationContext.xml為ClassPath根目錄下的文件。applicationContext.xml為Spring默認的配置文件名稱,默認存儲在ClassPath根目錄下。或者使用文件流加載任意位置的配置文件,並傳遞給XmlBeanFactory構造函數,例如:

InputStream is = new FileInputStream("C:\\ApplicationContext.xml");  // 獲取配置資源
XmlBeanFactory factory = new XmlBeanFactory(is); // 獲取對象工廠
IService hello = (IService)factory.getBean("service"); // 獲取對象

  或者用ClassPathXmlApplicationContext加載多個配置文件(多個配置文件以字符串數組形式傳入),並傳遞給XmlBeanFactory構造函數:

ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml", "applicationContext-part2.xml"}); // 多個配置
BeanFactory factory = (BeanFactory)appContext; // ApplicationContext繼承自BeanFactory接口

  XmlBeanFactory配置格式

  一個BeanFactory中配置了多個Bean。在XmlBeanFactory中,配置文件的根節點為<beans>,里面定義了幾個<bean>子節點,每個<bean>定義一個Bean。格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>    <!-- Beans根節點 -->
    <bean id="..." class="...">  <!--Bean節點,定義Bean-->
    ...
    </bean>
    <bean id="..." class="...">     <!--Bean節點,定義Bean-->
        <property name="..." value="..."></property>  <!-- Property定義屬性 -->
        <property name="..." ref="..."></property>  <!-- Property定義屬性 -->
    </bean>
</beans>

  配置Java Bean

  一個BeanDefinition定義一個Bean,在XML中對應一個<bean>標記。Spring通過<bean>配置來實例化Bean,設置Bean的屬性,以及設置Bean之間相互的依賴性。

  基本配置<bean>

   一個<bean>通常需要定義id與class屬性。class屬性是必須的,如果有其它Bean引用了該Bean,則id屬性是必須的。Bean之間通過id屬性相互訪問,如:

<bean id="exampleBean" class="example.ExampleBean"></bean>

  上面代碼等價於

ExampleBean exampleBean = new ExampleBean();

  其中,對象名exampleBean相當於配置中的id屬性。

  工廠模式factory-method

  如果一個Bean不能通過new直接實例化,而是通過工廠類的某個方法建的,可以把class設為工廠類,用factory-method指向創建對象的法:

<!-- createInstance()是靜態方法 -->
<bean id="exampleBean"
        class="example.MyFactoryBean"
        factory-method="createInstance" />

<!-- createInstance()是非靜態方法 -->
<bean id="exampleBean2"
        factory-bean="myFactoryBean"
        factory-method="createInstance" />

  構造函數<constructor-arg>

  如果Bean的構造函數帶參數,那就需指定參數,用<constructor-arg>指定

<bean id="exampleBean" class="examples.ExampleBean"><!-- 定義Bean -->
    <constructor-arg><ref bean="anotherExampleBean" /></constructor-arg><!-- 構造函數參數 -->
    <constructor-arg><ref bean="yetAnotherBean" /></constructor-arg><!-- 構造函數參數 -->
    <constructor-arg><value>1</value></constructor-arg><!-- 構造函數參數 -->
</bean>

  每個<constructor-arg>的參數的順序要與構造函數相同。

public class ExampleBean {
    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;
    public ExampleBean(AnotherBean beanOne, YetAnotherBean beanTwo, int i){
        this.beanOne = beanOne;
        this.beanTwo = beanTwo;
        this.i = i;
    }
}
        

  單態模式singleton

  Bean可以定義為單態模式(Singleton)。即在程序中只有一個實例,像數據源等一般設為單例。Spring默認是單態模式,如果想使用非單例模式(稱為Prototype模式),需把singleton屬性置為false:

<bean id="exampleBean" class="examples.ExampleBean" singleton="false" />

  非單例下,每次請求該Bean,都會生成一個新的對象。

  配置屬性<property>

  Spring通過Bean的setter方法設置屬性。因此,需要由Spring注射的屬性一般都具有公共的setter,getter方法。例如下面的配置代碼:

<bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="jdbc:mysql://localhost:3306/spring?characterEncoding=UTF-8" />
        <property name="username" value="root" />
        <property name="password" value="admin" />
    </bean>

  destroy-method屬性配置關閉方法。在銷毀對象時會調用該方法。

  注意:

<!-- 將password設為空字符串 -->
<property name="password"><value></value></property>
<!-- 將password設為null,也可以不設置 -->
<property name="password"><null /></property>

  設置對象屬性<ref>

  使用ref標簽配置Bean的id屬性使用。如:

<bean id="dao" class="com.helloweenvsfei.forum.dao.impl.DaoImpl">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean class="com.helloweenvsfei.forum.service.impl.ThreadServiceImpl">
    <property name="dao" ref="dao"></property>
</bean>

  ref的內容為引用的Bean的id屬性。

  也可使用內部配置(或者內聯配置),類似於JAVA中的匿名類對象。因為內部配置一般不會被其他的Bean引用,因此不需要配置內部Bean的id。例如:

<property name="dao">
    <bean class="example.DaoImpl"></bean>
</property>

  除了使用<ref>的bean屬性,還可以使用local、parent,它們與bean屬性的作用是一樣的。不同的是,local只能使用本配置文件中的bean,而parent只能使用父配置文件中的bean,但bean則沒有任何限制。

  配置List屬性<list>

  <list>配置java.util.List類型的屬性。list屬性中可配置任意類型對象,如果為java對象,使用ref指定,或者<bean>定義新實例,如果是普通類型如String,int,double等,直接用字符串即可。<list>中的元素會按配置的先后順序排序,例如:

<property name="someList">
    <list>
        <value>String,Integer,Double,Boolean等類型對象</value>
        <ref bean="myDataSource" />
    </list>
</property>

  配置Set屬性<set>

  <set>配置java.util.Set類型的屬性。Set屬性中可配置任意類型對象。如果為java對象,則使用<ref>指定,或者使用<bean>重新定義新實例。如果是普通類型如String,int,double等,直接用字符串即可。例如:

<property name="someSet">
    <set>
        <value>String,Integer,Double,Boolean等類型對象</value>
        <ref bean="myDataSource" />
    <set>
</property>

  配置Map屬性<map>

  <map>配置java.util.Map類型的屬性。<entry>配置Map里的元素,key指定索引,value指定值。如果為java對象,則使用ref指定,或者使用<bean>重新定義新實例,如果key為對象,,使用key-ref屬性,例如:

<property name="someMap">
    <map>
        <entry key="yup an entry">
            <value>just some string</value>
        </entry>
        <entry key-ref="myDataSource">
            <ref bean="serviceImpl" />
        </entry>
    </map>
</property>

  配置Properties屬性<props>

  使用<props>與<prop>配置Properties屬性。<props/>配置一個Properties對象,<prop/>配置一條屬性,屬性key配置索引,例如:

<props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.format_sql">false</prop>
    <prop key="hibernate.hbm2ddl.auto">create</prop>
</props>

  <idref>與<ref>的區別

  <idref>與<ref>的作用是一樣的,都是配置java對象的。<idref>的用法也與<ref>基本相同。不同的是,<idref>只有bean與local屬性,沒有parent屬性,如

<idref local="dataSource" />

  Spring加載XML配置文件時,會檢查<idref>配置的Bean存在不存在。而<ref>只會在第一次調用時才會檢查。換句話說,如果Bean不存在,<idref>能在啟動程序的時候就拋出錯誤,而<ref>只會在運行中拋出錯誤。

  設置destory-method銷毀方法

  有的對象(例如數據源,JDBC連接,輸入輸出流等)在使用完畢后需要執行close()方法釋放資源。可以使用destory-method配置。Spring在注銷這些資源時會調用destory-method里配置的方法。例如:

<bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
.....
</bean>

  設置depends-on依賴對象

  Spring默認按照配置文件里Bean配置的先后順序實例化Bean,但有時候在實例化A對象之前需要先實例化后面的B對象。這時候可以使用depends-on,強制先實例化B對象。如:

<bean id="a" class="examples.A" depends-on="b"></bean>
<bean id="b" class="examples.B"></bean>

  在實例化A的時候會檢查B的實例是否存在,如果不存在,先實例化B

  初始化方法init-method

  與destory-method相反,有的對象在實例化后需要執行某些初始化代碼,但這些初始化代碼不能寫在構造函數中。這時候可以把這部分初始化代碼寫在一個方法中,如init(),使用init-method屬性,強制Spring執行該方法進行初始化,如:

<bean id="c" class="example.C" init-method="init"></bean>

  屬性自動裝配autowire

  為了防止配置文件過大,可以使用autowire屬性

  配置autowire自動裝配

  使用<bean>的autowire屬性后,不需要再用<property name="" value="" />顯示地設置該Bean的屬性、依賴關系。Spring會根據反射,自動尋找符合條件的屬性,設置到該Bean屬性上。如果autowire設置為byType,將會按照屬性的類型自動匹配。如:

<bean id="d" class="examples.D" autowire="byType"></bean>

  autowire取值范圍

autowire屬性定義的不是需要自動裝配的屬性名,而是自動裝配的規則。一但配置,所有的屬性都將遵循autowire定義的規則。autowire所有的取值以及意義見下表

  如果顯示定義了<property>或者<constructor-arg>,會覆蓋默認裝配。自動裝配一般與下面的依賴檢查連用。

  注意:在大型項目中不推薦使用,因為自動裝配會隱藏依賴裝配的細節。降低可讀性與可維護性,並可能帶來意想不到的麻煩。

  依賴檢查dependency

  有時候某些Bean的屬性配置有錯誤,比如某個屬性沒有設置。這種錯誤在程序啟動的時候不會有任何異常表現,會一直潛伏到Spring調用該Bean時才會被發現。為了防止這種情況,Spring提供依賴檢查,在程序啟動的時候檢查依賴配置。如果有錯誤,啟動時就會拋出異常,以便發現配置錯誤。

  配置dependency依賴檢查

  依賴檢查能夠檢查屬性是否被設置。如果配置了依賴檢查,程序啟動時會進行配置校驗,以便及時地發現配置錯誤。通過設置<bean>的dependency-check設置依賴檢查規則,如:

<bean id="bean" class="examples.Bean" dependency-check="all"></bean>

  dependency屬性取值范圍

  dependency屬性有多種取值,分別應對不同的情況。但是需要注意,dependency依賴檢查是很生硬的,例如設置為object,將會檢查所有的java對象屬性,只要有一個屬性沒有設置,就會拋出異常,即某屬性明明不需要設置,但是沒法避免dependency檢查,容易造成“一竿子全打死”的現象。dependency的取值以及意義見表

  Bean的高級特性

  Spring程序中,JAVA Bean一般與Spring是非耦合的,不會依賴於Spring類庫。這也是Spring的優點。但有時候Java Bean需要知道自己在Spring框架中的一些屬性。Spring提供了一些接口,實例化Java Bean對象后Spring會調用接口的方法。

  BeanNameAware接口獲取Bean的id

  BeanNameAware接口幫助Java Bean知道自己在配置文件中的id,實現BeanNameAware,實現方法名為setBeanName()方法,初始化該對象后Spring就會執行該回調方法,將id設置進來。Bean中設置一個變量,接受id名稱即可,例如:

package com.helloweenvsfei.spring.example;

import org.springframework.beans.factory.BeanNameAware;

public class WhatsTheNameBean implements BeanNameAware {

    private String beanName;

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

}

  提示:setBeanName()方法的回調發生在所有參數被設置完之后,初始化方法(init-method屬性)被執行之前。

  BeanFactoryAware接口獲取BeanFactory

  BeanFactoryAware接口幫助java Bean知道哪個BeanFactory實例化了自己,BeanFactoryAware接口中有setBeanFactory的回調方法,初始化該對象后,會回調該方法,將BeanFactory傳遞進來。BeanFactoryAware接口的代碼如下:

public interface BeanFactoryAware{
    void setBeanFactory(BeanFactory beanFactory) throws BeanException
}

  用法同BeanNameAware,實現了BeanFactoryAware接口的Java Bean能夠獲取到BeanFactory,從BeanFactory中能夠獲取到BeanFactory中配置的其他Java Bean。Spring不推薦這樣做,因為這樣會與Spring耦合。獲取其它Java Bean一般通過設置getter、setter方法,用依賴注入實現

  InitializingBean接口執行初始化方法

  實現了InitializingBean接口的Java Bean會在實例后、所有屬性被設置后調用初始化方法。但使用該接口會與Spring代碼發生耦合,因此不推薦使用。InitializingBean接口代碼如下:

public interface InitializingBean{
    public void afterPropertiesSet();
}

  Spring推薦使用init-method配置,效果等價:

<bean id="d" class="examples.D" init-method="afterPropertiesSet"></bean>

  DisposableBean接口執行銷毀方法

  實現了DisposableBean接口的Java Bean會在對象丟棄的時候調用銷毀方法。但使用該接口會與Spring代碼發生耦合,因此不推薦使用。DisposableBean接口代碼如下:

public interface DisposableBean{
    void destory() throws Exception;
}

  Spring推薦使用destory-method配置,效果等價:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-method="close"></bean>

  BeanFactory高級特性

  如果Java Bean實現了BeanFactoryAware接口,就能夠獲得BeanFactory對象。BeanFactory有下面幾個常用的方法:

  屬性覆蓋器

  對於一些參數,更實用更簡單的方法是使用properties配置,而不是配置在Spring的配置文件中。Spring提供屬性替代配置,允許把某些屬性配置在properties文件中。

  配置PropertyOverrideConfigurer屬性覆蓋器

  PropertyOverrideConfigurer允許把XML配置里的某些參數配置到properties文件中。這在數據庫配置中很常見。配置時需要配置一個PropertyOverrideConfigurer對象,指定properties文件的位置,然后把替換的屬性用形如${jdbc.url}的字符串替代,如:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:jdbc.properties" />
</bean>

  PropertyOverrideConfigurer對象會到指定名稱的properties文件(例如jdbc.properties)中,尋找屬性名為${}變量的配置,${}中最好不要有空格

  properties配置

  具體的數據庫配置是寫在jdbc.properties里面的。properties中的配置比applicationContext.xml中更便於閱讀、修改與維護。代碼如下:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/forum?characterEncoding=UTF-8
jdbc.username=root
jdbc.password="admin

 


免責聲明!

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



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