《Spring攻略(第2版)》——1.11 用XML配置自動裝配Bean
本節書摘來自異步社區《Spring攻略(第2版)》一書中的第1章,第1.11節,作者: 【美】Gary Mak , Josh Long , Daniel Rubio著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看
1.11 用XML配置自動裝配Bean
1.11.1 問題
當一個Bean需要訪問另一個Bean時,你可以顯式指定引用裝配它。但是,如果你的容器能夠自動裝配Bean,就可以免去手工配置裝配的麻煩。
1.11.2 解決方案
Spring IoC容器能夠幫助你自動裝配Bean。你隻要在的autowire屬性中指定自動裝配模式就可以了。表1-2列出了Spring支持的自動裝配模式。
*默認模式是no,但是可以設置根元素的default-autowire屬性修改。這個默認模式將被Bean自己指定的模式覆蓋。
盡管自動裝配功能非常強大,但代價是降低了Bean配置的可讀性。因為自動裝配由Spring在運行時執行,你無法從Bean配置文件中得到Bean裝配的方式。在實踐中,我們建議僅將自動裝配應用到組件依賴不複雜的應用程序中。
1.11.3 工作原理
按照類型的自動裝配
你可以將sequenceGenerator bean的autowire屬性設置為byType並且不設置prefixGenerator屬性。然後,Spring將試圖裝配類型與PrefixGenerator兼容的Bean。在這個例子中,將自動裝配datePrefixGenerator bean。
<beans ...>
<bean
autowire="byType">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
</bean>
<bean
>
<property name="pattern" value="yyyyMMdd" />
</bean>
</beans>
按照類型的自動裝配的主要問題是有時候在IoC類型中具有超過一個與目標類型兼容的Bean。在這種情況下,Spring將無法確定哪個Bean最適合於該屬性,從而無法進行自動裝配。例如,如果你有另一個以當前年份作為前綴的前綴生成器,按照類型的自動裝配將會立即被破壞。
<beans ...>
<bean
autowire="byType">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
</bean>
<bean
>
<property name="pattern" value="yyyyMMdd" />
</bean>
<bean
>
<property name="pattern" value="yyyy" />
</bean>
</beans>
如果找到超過一個可供自動裝配的Bean,Spring將會拋出一個UnsatisfiedDependency Exception異常。
Exception in thread "main"
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sequenceGenerator' defined in class path resource [beans.xml]: Unsatisfied dependency expressed through bean property 'prefixGenerator': No unique bean of type [com.apress.springrecipes.sequence.PrefixGenerator] is defined: expected single matching bean but found 2: [datePrefixGenerator, yearPrefixGenerator]
按照名稱的自動裝配
byName是另一種自動裝配模式,有時候它能解決按照類型的自動裝配的問題。它的工作方式與byType類似,但是這時候,Spring將試圖裝配一個類名與該屬性名相同的Bean,而不是兼容的類型。因為Bean的name屬性在一個容器中是唯一的,按照名稱的自動裝配不會導致歧義。
<beans ...>
<bean
autowire="byName">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
</bean>
<bean
>
<property name="pattern" value="yyyyMMdd" />
</bean>
</beans>
但是,按照名稱的自動裝配並不能工作於任何情況。有時候,你不可能使目標Bean的名稱與屬性相同。在實踐中,你往往必須在保持其他依賴自動裝配的同時明確地指定歧義的依賴。這意味著你混合了顯式裝配和自動裝配。
按照構造程序的自動裝配
constructor自動裝配模式與byType的工作方式類似,但是更複雜一些。對於具有單個構造程序的Bean,Spring將試圖為每個構造程序參數裝配一個具有兼容類型的Bean。但是對於具有多個構造程序的Bean,這一過程就更加複雜。Spring首先試圖為每個構造程序的每個參數找到一個類型兼容的Bean。然後,將選擇具有最多匹配參數的構造程序。
假定SequenceGenerator有一個默認構造程序和一個具有參數PrefixGenerator的構造程序。
package com.apress.springenterpriserecipes.sequence;
public class SequenceGenerator {
public SequenceGenerator() {}
public SequenceGenerator(PrefixGenerator prefixGenerator) {
this.prefixGenerator = prefixGenerator;
}
...
}
在這種情況下,第二個構造程序匹配並且被選中,因為Spring可以找到一個類型與Prefix Generator兼容的Bean。
<beans ...>
<bean
autowire="constructor">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
</bean>
<bean
>
<property name="pattern" value="yyyyMMdd" />
</bean>
</beans>
但是,一個類中的多個構造程序可能造成構造程序參數匹配的歧義。如果你要求Spring確定一個構造程序,情況可能更加複雜。所以,如果你使用這種自動裝配模型,就要非常小心地避免歧義。
自動檢測的自動裝配
自動裝配模式autodetect要求Spring在byType和constructor模式中作出決定。如果至少找到一個沒有參數的默認構造程序,將選擇byType模式,否則,將選擇constructor模式。因為SequenceGenerator類定義了默認的構造程序,將選擇byType模式。這意味著前綴生成器將通過設值方法注入。
<beans ...>
<bean
autowire="autodetect">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
</bean>
<bean
>
<property name="pattern" value="yyyyMMdd" />
</bean>
</beans>
自動裝配與依賴檢查
你已經看到,如果Spring找到超過一個候選的自動裝配Bean,將會拋出UnsatisfiedDependency Exception異常。另一方麵,如果自動裝配模式設置為byName或byType,而Spring無法找到匹配的Bean進行裝配,將把該屬性保持為未設置狀態,這可能導致一個NullPointerException異常或者一個值沒有初始化。但是,如果你希望在自動裝配無法裝配的Bean時得到通知,應該將dependency-check屬性設置為objects或者all。
在這種情況下,如果自動裝配無效將會拋出UnsatisfiedDependencyException異常。objects將通知Spring在相同的Bean工廠中無法找到協同Bean時發出一個錯誤。all通知容器在任何作為依賴的簡單屬性類型(String類型或者原始類型)未被設置時發出一個錯誤,這補充了objects的功能。
<bean
autowire="byName" dependency-check="objects">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
</bean>
最後更新:2017-05-31 15:31:36