Spring中Bean的配置

先從IOC提及,這個概念實際上是從咱們日常new一個對象的對立面來講的,咱們日常使用對象的時候,通常都是直接使用關鍵字類new一個對象,那這樣有什 麼壞處呢?其實很顯然的,使用new那麼就表示當前模塊已經不知不覺的和new的對象耦合了,而咱們一般都是更高層次的抽象模塊調用底層的實現模塊,這樣 也就產生了模塊依賴於具體的實現,這樣與咱們JAVA中提倡的面向接口面向抽象編程是相沖突的,並且這樣作也帶來系統的模塊架構問題。很簡單的例子,咱們 在進行數據庫操做的時候,老是業務層調用DAO層,固然咱們的DAO通常都是會採用接口開發,這在必定程度上知足了鬆耦合,使業務邏輯層不依賴於具體的數 據庫DAO層。可是咱們在使用的時候仍是會new一個特定數據庫的DAO層,這無形中也與特定的數據庫綁定了,雖然咱們可使用抽象工廠模式來獲取DAO 實現類,但除非咱們一次性把全部數據庫的DAO寫出來,不然在進行數據庫遷移的時候咱們仍是得修改DAO工廠類。

    那咱們使用IOC能達到什麼呢?IOC,就是DAO接口的實現再也不是業務邏輯層調用工廠類去獲取,而是經過容器(好比spring)來自動的爲咱們的業務 層設置DAO的實現類。這樣整個過程就反過來,之前是咱們業務層主動去獲取DAO,而如今是DAO主動被設置到業務邏輯層中來了,這也就是反轉控制的由 來。經過IOC,咱們就能夠在不修改任何代碼的狀況下,無縫的實現數據庫的換庫遷移,固然前提仍是必須得寫一個實現特定數據庫的DAO。咱們把DAO廣泛 到更多的狀況下,那麼IOC就爲咱們帶來更大的方便性,好比一個接口的多個實現,咱們只須要配置一下就ok了,而不須要再一個個的寫工廠來來獲取了。這就 是IOC爲咱們帶來的模塊的鬆耦合和應用的便利性。 java

那爲何說IOC很簡單呢?說白了其實就是由咱們日常的new轉成了使用反射來獲取類的實例,相信任何人只要會用java的反射機制,那麼本身寫一個IOC框架也不是不可能的。好比:

……
public Object getInstance(String className) throws Exception
{
    Object obj = Class.forName(className).newInstance();
    Method[] methods = obj.getClass().getMethods();
    for (Method method : methods) {
        if (method.getName().intern() == "setString") {
            method.invoke(obj, "hello world!");
        }
    }
}
…… web

  上面的一個方法咱們就很簡單的使用了反射爲指定的類的setString方法來設置一個hello world!字符串。其實能夠看到IOC真的很簡單,固然了IOC簡單並不表示spring的IOC就簡單,spring的IOC的功能強大就在於有一系 列很是強大的配置文件維護類,它們能夠維護spring配置文件中的各個類的關係,這纔是spring的IOC真正強大的地方。在spring的Bean 定義文件中,不只能夠爲定義Bean設置屬性,還支持Bean之間的繼承、Bean的抽象和不一樣的獲取方式等等功能。 spring

在spring的Bean配置中總的來講其實就一個標籤<bean></bean>,這個bean標籤就攘括了幾乎全部的配置, 而後bean的繼承、抽象等都是基於此標籤之上的,掌握了bean的配置,詳細可使本身有一個比較大的提高,尤爲是對於新手來講(我也是,呵呵  )。最基礎的bean配置以下:

<bean id="bean_test" class="cn.qtone.test.HelloWorld"></bean>

    這裏咱們就簡單的使用HelloWorld類來實例化,使用默認的構造方法,即至關於咱們使用:

HelloWorld tmp = new HelloWorld();  數據庫

但有一點不一樣的是在spring配置中的在整個應用期間只有一個實例,便是單例的,固然這個單例是指對一個IOC容器(spring)來講的,而不是咱們一般說說的單態模式。固然,spring也能夠這樣配置不是單態的實例,好比咱們修改以下:

<bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype"></bean>

  spring中scope默認的是單態(singleton),固然針對web應用程序,還能夠配置爲request、session等範圍。至於什 麼時候使用什麼權限範圍就要看應用程序的使用了,好比在多線程程序中,單態是否會對程序有所影響就須要考慮了。 編程

若是HelloWorld類沒有空的構造方法,只有以下的兩個構造方法,那咱們該如何配置呢?

……
public HelloWorld(String str)
{
    ……
}

public HelloWorld(Date date, int i)
{
    ……
}
……

    因爲沒有默認構造方法,因此咱們就須要在bean的配置中寫上構造參數才能夠,以下:

<!-- 使用一個參數的構造 -->
<bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype">
    <constructor-arg><value>hello</value></constructor-arg>
</bean> session

   上面說的使用一個參數的,即帶字符串參數的構造方法,若是想使用帶日期和整型的構造方法,那麼就要作以下的配置了:

<bean id="bean_date" class="java.util.Date" />

<!-- 使用二個參數的構造 -->
<bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype">
    <constructor-arg ref="bean_date"></constructor-arg>
    <constructor-arg><value>345</value></constructor-arg>
</bean>  多線程


注意到上面的配置中咱們使用了ref關鍵字,這個是表示引用配置文件中的ID爲bean_date的對象,另外對於類型,spring會作恰當的轉換,比 如將345轉換成數字等。固然,這樣對簡單的構造來講不會有什麼問題,若是狀況比較複雜的話,那麼通常建議使用序號來標定,以下:

<!-- 使用二個參數的構造 -->
<bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype">
    <constructor-arg index="0" ref="bean_date"></constructor-arg>
    <constructor-arg index="1"><value>345</value></constructor-arg>
</bean> 架構

這樣,使用index屬性表示該參數所在位置了後,不管是spring構造起來,仍是咱們查看都會很方便。固然,spring也提供了自動查找,也就是依 賴查找的功能,可是這個我以爲你們仍是少用,由於這樣會使整個配置文件看起來很是的不直觀,並且不清晰,說不定過了一段時間再去看的時候就不知道是什麼意 思了,在正式應用項目中,仍是將各個bean的關係進行組織和編寫清楚爲好。 框架


上面所說的都是構造來實例化一個bean,但有時候咱們都會使用工廠模式來獲取bean。對於工廠模式,咱們通常也使用靜態工廠模式和實例工廠模式,這兩個在spring中配置也是不太同樣的。對於靜態工廠模式來實例化bean的,咱們的配置以下: spa

<bean id="bean_string" class="cn.qtone.test.TestFactory" factory-method="getBean"/>

    固然,咱們也能夠爲靜態工廠模式的bean來使用構造參數,這個就不說了。咱們上面的bean配置對應的實際代碼就應該是:

……
public static Object getBean()
{
    return "hello world";
}
……

那麼spring在實例化ID爲bean_string的bean時,就會使用TestFactory的getBean()方法來獲取,並且 TestFactory是沒有被實例化的,便是使用靜態方法來獲取的。對於實例工廠模式的話,咱們的配置和上面就稍微有點不同了,那咱們就應該配置兩個 bean, 一個是實例的工廠bean,還一個就是咱們要獲取的bean的配置了,以下:

<bean id="bean_factory" class="cn.qtone.test.TestBeanFactory"/>

<bean id="bean_helloWorld" factory-bean="bean_factory" factory-method="getHello"/>

  上面的配置中,spring容器將首先實例化一個TestBeanFactory,而後再根據該類的方法getHello來獲取一個bean的實例,咱們這裏以HelloWorld對象爲例,對應的代碼就應該以下:

……
public HelloWorld getHello()
{
    return new HelloWorld();
}
……

注意到,咱們這裏的getHello方法並非靜態方法,而是實例方法,因此必須先實例化TestBeanFactory後纔可以調用。

    上面說的都是如何去實例化一個bean,沒有說到bean的屬性注入。雖然咱們也能夠經過構造的時候進行一次注入,但這樣作不只失去了靈活性,並且一長串 的構造參數看着也眼疼哈,呵呵。固然,有一種狀況下,咱們是應該使用構造注入的,就是但願注入的對象不可以被外界修改時,咱們這時候就必須使用構造注入 了。對於bean的屬性注入,以HelloWorld爲例,咱們能夠簡單的配置以下:

<bean id="bean_test" class="cn.qtone.test.HelloWorld">
    <property name="hello" value="你好!" />
    <property name="world" value="世界" />
    <property name="date" ref="bean_date" />
</bean>


  上面的配置中使用了三個屬性注入,即spring中的setter注入方式。注意第三個屬性,使用了ref,代表這個date屬性的設置參數是關聯到ID 爲bean_date的bean上去的。注意在使用setter注入的時候,屬性的名稱不是方法的全名稱,而是知足javaBean規範的命名方式,即如 果屬性名稱爲xxx,那麼其對應的方法名稱就應該是:setXxx(),注意的是除了xxx中第一個字符不區分大小寫以外,其餘的是要嚴格區分的。那麼對 照上面的配置,咱們的HelloWorld的方法就應該以下:

……
public void setHello(String hello)
{
    ……
}

public void setWorld(String world)
{
    ……
}

public void setDate(Date date)
{
    ……
}
……

使用setter注入的好處就是能夠很清晰的知道每個注入的是什麼參數和意義,經過名稱就能夠很容易的看出來,這也是spring提倡使用setter注入的緣由之一。

相關文章
相關標籤/搜索