Spring-方法注入、depends-on、自動裝配協作物件
方法注入
對於大部分的使用者來說,容器中多數的bean是singleton的。當一個singleton的bean需要同另一個singleton的bean合作(使用)時,或者一個非singleton的bean需要同另外一個非singleton的bean合作的時候,通過定義一個bean為另一個bean的屬性來處理這種依賴關係就足夠了。然而當bean的生命週期不同的時候就有一個問題。想象一下一個singleton bean A ,或許在每次方法呼叫的時候都需要使用一個non-singleton bean B。容器僅僅會建立這個singleton bean A一次,因此僅僅有一次的機會去設定它的屬性。因此容器沒有機會每次去為bean A提供新的bean B例項。
一個解決這個問題的方法是放棄一些反向控制。Bean A可以通過實現BeanFactoryAware知道容器的存在,使用程式設計的手段在需要的時候通過呼叫getBean(“B”)來向容器請求新的bean B例項。因為bean的程式碼知道Spring並且耦合與Spring,所以這通常不是一個好的方案。
方法注入,BeanFactory的高階特性之一,可以以清潔的方式處理這種情況以及其他一些情況。
Lookup方法注入
Lookup方法注射指容器能夠重寫容器中bean的抽象或具體方法,返回查詢容器中其他bean的結果。被查詢的bean在上面描述的場景中通常是一個non-singleton bean (儘管也可以是一個singleton的)。Spring通過使用CGLIB庫在客戶端的類之上修改二進位制碼,從而實現上述的場景要求。
包含方法注入的客戶端類,必須按下面的形式抽象(具體)定義方法:
protected abstract SingleShotHelper createSingleShotHelper();
如果方法不是抽象的,Spring就會直接重寫已有的實現。在XmlBeanFactory的情況下,可以使用bean定義中的lookup-method屬性來指示Spring去注入/重寫這個方法,以便從容器返回一個特定的bean。
舉個例子說明:
<!--a stateful bean deployed as a prototype(non-singleton)-->
<bean id="singleShotHelper" class="..." singleton="false">
</bean>
<!--myBean uses singleShotHelper-->
<bean id="myBean" class="">
<lookup-method name="createSingleShotHelper"
bean="singleShotHelper"/>
<property>
...
</property>
</bean>
當myBean需要一個新的singleShotHelper的例項的時候,它就會呼叫它自己的createSingleShotHelper方法。值得注意的是:部署beans的人員必須小心地將singleShotHelper作為一個non-singleton部署(如果確實需要這麼做)。如果它作為一個singleton(除非明確說明,否則預設就是singleton)而部署,同一個singleShotHelper例項將會每次被返回。
注意Lookup方法注射能夠同構造函式注射結合(對建立的bean提供可選的建構函式引數),也可以同setter方法注射結合(在建立的bean之上設定屬性)。
任意方法的替換
另一種方法注射沒有lookup方法注入用的多,它用另一個方法實現替換被管理bean的任意一個方法。使用者可以放心跳過這一節(這是個有點高階的特性),除非這個功能確實需要。
在一個XMLBeanFactory中,對於一個被部署的bean,replaced-method元素可以用來把已存在的方法實現替換為其他的實現。考慮如下的類,有一個我們想要重寫的computeValue方法:
...
public class MyValueCalculator{
public String computeValue(String input){
...some real code
}
...some other methods
}
需要為新方法定義提供實現 org.springframework.beans.factory.support.MethodReplacer介面的類。
/**meant to be used to override the existing computeValue implementation in MyValueCalculator*/
public class ReplacementComputeValue implements MethodReplacer{
public Object reimplement(Object o,Method m,Object[] args)throws Throwable{
//get the input value,work with it,and return a computed result
String input = (String) arg[0];
...
return ...;
}
}
部署原始的類和指定方法重寫的BeanFactory部署定義像下面所示的:
<bean id="myValueCalculator" class="x.y.x.MyValueCalculator">
<!--arbitrary method replacement-->
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="replacementComputeValue" class="a.b.c.ReplaceMentComputeValue">
</bean>
replaced-method元素中的一個或多個arg-type元素用來表示,這個被過載方法的方法簽名。注意,引數的簽名只有在方法被過載並且該方法有多個不同形式的時候才真正需要。為了方便,引數的型別字串可以使全限定名的子字串。比如,以下的都匹java.lang.String。
java.lang.String
String
Str
因為引數的個數通常就足夠區別不同的可能,所以僅僅使用匹配引數的最短的字串能夠節省很多鍵入工作。
使用depends-on
對於大多數的情況,一個bean被另一個bean依賴,是由於這個bean是否被當作其他bean的屬性來表達的。在XmlBeanFactory中,它是通過ref元素來完成的。與這種方式不同的是,有時一個知道容器的bean僅僅會被給與它所依賴的id(使用一個字串值或等價的idref元素)。接著第一個bean就以程式設計的方式向容器請求它的依賴。在兩種情況下,被依賴的bean都會在依賴它的bean之前被恰當地初始化。
對於相對罕見的情況,beans之間的依賴不夠直接(舉例,當一個類中的靜態初始塊需要被觸發,比如資料庫驅動的註冊),depends-on元素可以用來在初始化使用這個元素的bean之前,強制一個或多個beans初始化。
下面是一個配置的例子:
<bean id="beanOne" class="ExampleBean" depends-on="manager">
<property name="manager"><ref local="manager"/></property>
</bean>
<bean id="manager" class="ManagerBean"/>
自動裝配協作物件
BeanFactory能夠自動裝配合作bean之間的關係。這就意味著,讓Spring通過檢查BeanFactory的內容來自動裝配你的bean的合作者(也就是其他的bean)。自動裝配功能有5種模式。自動裝配可以指定給每一個bean,因此可以給一些bean使用而其他的bean不再自動裝配。通過使用自動裝配,可以減少(或者消除)指定屬性(或構造引數)的需要,顯著節省鍵入工作。在XmlBeanFactory中,使用bean元素的autowire屬性來指定bean定義的自動裝配模式。以下是允許的值。
模式 |
解釋 |
no |
不使用自動裝配。Bean的引用必須通過ref元素定義。這是預設的配置, |
byName |
通過屬性名字進行自動裝配。這個選項會檢查BeanFactory,查詢一個與 |
byType |
如果BeanFactory中正好有一個同屬性型別一樣的bean,就自動裝配這個 |
constructor |
這個同byType類似,不過是應用於建構函式的引數。如果在BeanFactory中不是恰好有一個bean與建構函式引數相同型別,則一個致命的錯誤會產生。 |
autodetect |
通過對bean檢查類的內部來選擇constructor或byType。如果找到一個預設的建構函式,那麼就會應用byType。 |
注意:顯示的指定依賴,比如property和constructor-arg元素,總彙覆蓋自動裝配。自動裝配的行為可以和依賴檢查結合使用,依賴檢查會在自動裝配完成後發生。
注意:正如我們已經提到過的,對於大型的應用,自動裝配不鼓勵使用,因為它去除了你的合作類的透明性和結構。