注:spring 4.0 再也不支持 ref local 標籤。(參考:http://blog.csdn.net/fo11ower/article/details/51162312)html
1.簡介java
org.springframework.beans 及 org.springframework.context 包是 Spring IoC 容器的基礎。Blinux
BeanFactory 提供的高級配置機制,使得管理任何性質的對象成爲可能。ApplicationContext 是 BeanFactory 的擴展,功能獲得了進一步的增強。簡而言之,BeanFactory 提供了配置框架及基本功能,而 ApplicationContext 徹底由 BeanFactory 擴展而來,於是 BeanFactory 所具有的能力和行爲也適用於 ApplicationContext。web
2.容器和 bean 的基本原理spring
在 Spring 中,那些組成應用的主體及由 Spring IoC 容器所管理的對象被稱之爲 bean。簡單的講,bean 就是由 Spring 容器初始化、裝配及被管理的對象。而 bean 定義以及 bean 相互間的依賴關係將經過配置元數據來描述。編程
2.1容器api
org.springframework.factory.BeanFactory 是 SpringIoC 容器的實際表明者,IoC 容器負責容納此前所描述的 bean,並對 bean 進行管理。數組
在 Spring 中,BeanFactory 是 IoC 容器的核心接口。它的職責包括:實例化、定位、配置應用程序中的對象及創建這些對象間的依賴。session
Spring 提供了不少易用的 BeanFactory 實現,XmlBeanFactory 就是最經常使用的一個。http://docs.spring.io/spring/docs/current/javadoc-api/app
2.1.1配置元數據
從上圖能夠看到,Spring IoC 容器將讀取配置元數據;並經過它對應用中各個對象進行實例化、配置及組裝。
Spring 支持三種配置元數據格式:XML 格式、Java 屬性文件格式或使用 Spring 公共 API 編程實現。一般狀況下咱們使用簡單直觀的 XML 來做爲配置元數據的描述格式。
Spring IoC 容器能夠經過多種途徑來加載配置元數據,好比本地系統、Java Classpath 等。
Spring IoC 容器至少包含一個 bean 定義,但大多數狀況下會有多個 bean 定義。
bean 定義與應用程序中實際使用的對象一一對應。一般狀況下 bean 的定義包括:服務層對象、數據訪問層對象(DAO)、相似 Structs Action 的表示層對象、Hibernate SessionFactory 對象、JMS Queue 對象等等。
如下是一個基於 XML 配置元數據的基本結構:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"> 6 7 <bean id="ioCDemo01" class="demo.ioc.IoCDemo01" > 8 </bean> 9 10 </beans>
2.2實例化容器
1 package demo.ioc; 2 3 import org.springframework.beans.factory.BeanFactory; 4 import org.springframework.beans.factory.xml.XmlBeanFactory; 5 import org.springframework.context.ApplicationContext; 6 import org.springframework.context.support.ClassPathXmlApplicationContext; 7 import org.springframework.core.io.ClassPathResource; 8 import org.springframework.core.io.FileSystemResource; 9 import org.springframework.core.io.Resource; 10 11 public class Test { 12 13 public static void main(String[] args) { 14 String fileName = "applicationContext.xml"; 15 16 //1 17 // Resource resource = new FileSystemResource(fileName); 18 // BeanFactory factory = new XmlBeanFactory(resource); 19 20 //2 21 // ClassPathResource resource = new ClassPathResource(fileName); 22 // BeanFactory factory = new XmlBeanFactory(resource); 23 24 //3 25 ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{fileName}); 26 BeanFactory factory = (BeanFactory) context; 27 28 IoCDemo01 ioCDemo01 = (IoCDemo01) factory.getBean("ioCDemo01"); 29 ioCDemo01.show(); 30 } 31 32 }
2.2.1組成基於 XML 配置元數據
將 XML 配置文件分拆成多個部分是很是有用的。爲了加載多個 XML 文件生成一個 ApplicationContext 實例,能夠將文件路徑做爲字符串數組傳給 ApplicationContext 構造器。而 beanfactory 將經過調用 bean defintion reader 從多個文件中讀取 bean 定義。
一般狀況下,更傾向於上述作法,由於這樣各個配置並不會查覺到與其餘配置文件的組合。另一種方法是使用一個或多個的 <import /> 元素來從另一個或多個文件加載 bean 定義。全部的 <import /> 元素必須放在 <bean /> 元素以前以完成 bean 的導入。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"> 6 7 <import resource="applicationContext2.xml"/> 8 9 <bean id="ioCDemo01" class="demo.ioc.IoCDemo01" > 10 </bean> 11 12 </beans>
2.3多種 bean
Spring IoC 容器管理一個或多個 bean,這些 bean 將經過配置文件中的 bean 定義被建立。
在容器內部,這些 bean 的定義由 BeanDefinition 對象來表示,該定義將包含如下信息:
全限定類名:這一般就是已定義 bean 的實際實現類。若是一般調用 static factory 方法來實例化 bean,而不是使用常規的構造器,那麼類名實際上就是工廠類的類名。
bean 行爲的定義,即建立模式(prototype 仍是 singleton)、自動裝配模式、依賴檢查模式、初始化及銷燬方法。這些定義將決定 bean 在容器中的行爲。
用於建立 bean 實例的構造器參數及屬性值。好比使用 bean 來定義鏈接池,能夠經過屬性或者構造參數指定鏈接數,以及鏈接池大小限制等。
bean 之間的關係,即協做(或者稱依賴)。
除了經過 bean 定義來描述要建立的指定 bean 的屬性以外,某些 BeanFactory 的實現也容許將那些非 BeanFactory 建立的、已有的用戶對象註冊到容器中,好比使用 DefaultListableBeanFactory 的 registerSingleton(..) 方法。不過大多數應用仍是採用元數據定義爲主。
2.3.1命名 bean
bean 的命名採用標準的 Java 命名約定,即小寫字母開頭,首字母大寫間隔的命名方式。
對 bean 採用統一的命名約定將會使配置更加簡單易懂。並且在使用 Spring AOP 時,若是要發通知(advice)給一組名稱相關的 bean 時,這種簡單的命名方式會受益不淺。
每一個 bean 都有一個或多個 id(或稱之爲標識符或名稱)。這些 id 在當前 IoC 容器中必須惟一。若是一個 bean 有多個 id,那麼其餘的 id 在本質上將被認爲是別名。
當使用基於 XML 的配置元數據時,將經過 id 或 name 屬性來指定 bean 標識符。id 屬性具備惟一性,並且是一個整整的 XML ID 屬性,所以其餘 xml 元素在引用該 id 時,能夠利用 XML 解析器的驗證功能。一般狀況下最好爲 bean 指定一個 id。儘管 XML 規範規定了 XML ID 命名的有效字符,可是 bean 標識符的定義不受該限制,由於除了使用指定的 xml 字符來做爲 id,還能夠爲 bean 指定別名,要實現這一點能夠在 name 屬性中使用逗號、冒號或者空格將多個 id 分隔。爲一個 bean 提供一個 name 並非必須的,若是沒有指定,那麼容器將爲其生成一個惟一的 name。
2.3.1.1bean 的別名
在對 bean 進行定義時,除了使用 id 屬性來指定名稱以外,爲了提供多個名稱,須要經過 alias 屬性來加以指定。
在定義 bean 時就指定全部的別名並不老是恰當的。有時咱們指望能在當前位置爲那些在別處定義的 bean 引入別名。在 XML 配置文件中,能夠單獨的 <alias /> 元素來完成 bean 別名的定義。
1 <alias name="ioCDemo01" alias="a1"/>
2.3.2實例化bean
當須要的時候,容器會從 bean 定義列表中取得一個指定的 bean 定義,並根據 bean 定義裏面的配置元數據使用反射機制來建立一個實際的對象。
當採用 XML 描述配置元數據時,將經過 <bean /> 元素的 class 屬性來指定實例化對象的類型。class 屬性一般是必須的(實例工廠方法實例化和 bean 定義的繼續除外)。
class 屬性主要有兩種用途:在大多數狀況下,容器將直接經過反射調用指定類的構造器來建立 bean;在極少數狀況下,容器將調用類的靜態工廠方法來建立 bean 實例,class 屬性將用來指定實際具備靜態工廠方法的類。
2.3.2.1用構造器來實例化
1 <bean id="ioCDemo01" class="demo.ioc.IoCDemo01" > 2 </bean>
2.3.2.2使用靜態工廠方法實例化
1 <bean id="calendar01" class="java.util.Calendar" factory-method="getInstance"> 2 </bean>
2.3.2.3使用實例工廠方法實例化
與使用靜態工廠方法實例化相似,用來進行實例化的實例工廠方法位於另一個已有的 bean 中,容器將調用該 bean 的工廠方法來建立一個新的 bean 實例。
爲使用此機制,class 屬性必須爲空,而 factory-bean 屬性必須制定爲當前(或其祖先)容器中包含工廠方法的 bean 的名稱,而該工廠 bean 的方法自己經過 factory-method 屬性來設定。
1 <bean id="clazz01" class="java.lang.Class" factory-method="forName"> 2 <constructor-arg> 3 <value>demo.ioc.IoCDemo01</value> 4 </constructor-arg> 5 </bean> 6 7 <bean id="ioCDemo012" factory-bean="clazz01" factory-method="newInstance"> 8 </bean>
雖然設置 bean 屬性的機制仍然在這裏被說起,但隱式的作法是由工廠 bean 本身來管理以及經過依賴注入(DI)來進行配置。
2.4使用容器
BeanFactory 提供六種方法供客戶代碼調用:
3.依賴
3.1注入依賴
依賴注入(DI)背後的基本原理是對象之間的依賴關係(即一塊兒工做的其餘對象)只會經過如下幾種方式來實現:構造器的參數、工廠方法的參數,或給由構造函數或者工廠方法建立的對象設置屬性。所以,容器的工做就是建立 bean 時注入那些依賴關係。相對於由 bean 本身來控制其實例化、直接在構造器中指定依賴關係或者相似服務定位器模式這 3 種自主控制依賴關係注入的方法來講,控制從根本上發生了倒轉,這也正是控制反轉名字的由來。
DI 主要有兩種注入方式,即 Setter 注入和構造器注入。
3.1.1Setter 注入
經過調用無參構造器或無參 static 工廠方法實例化 bean 以後,調用該 bean 的 setter 方法,便可實現基於 setter 的 DI。
1 <bean id="setter01" class="demo.ioc.di.SetterDemo01"> 2 <property name="a01"> 3 <ref bean="di01"/> 4 </property> 5 <property name="no"> 6 <value>1001</value> 7 </property> 8 </bean> 9 10 <bean id="di01" class="demo.ioc.di.A01"> 11 <property name="description"> 12 <value>AAAAA</value> 13 </property> 14 </bean>
1 package demo.ioc.di; 2 3 public class SetterDemo01 { 4 5 private A01 a01; 6 7 private int no; 8 9 public A01 getA01() { 10 return a01; 11 } 12 13 public void setA01(A01 a01) { 14 this.a01 = a01; 15 } 16 17 public int getNo() { 18 return no; 19 } 20 21 public void setNo(int no) { 22 this.no = no; 23 } 24 25 @Override 26 public String toString() { 27 return "SetterDemo01 [a01=" + a01.getDescription() + ", no=" + no + "]"; 28 } 29 30 31 32 }
1 package demo.ioc.di; 2 3 public class A01 { 4 5 private String description; 6 7 public String getDescription() { 8 return description; 9 } 10 11 public void setDescription(String description) { 12 this.description = description; 13 } 14 15 }
3.1.2構造器注入
基於構造器的 DI 經過調用帶參數的構造器來實現,每一個參數表明着一個協做者。此外,還可經過給靜態工廠方法傳參數來構造 bean。
1 <bean id="di01" class="demo.ioc.di.A01"> 2 <property name="description"> 3 <value>AAAAA</value> 4 </property> 5 </bean> 6 7 <bean id="constructDemo01" class="demo.ioc.di.ConstructDemo01"> 8 <constructor-arg type="String" value="Tom"> 9 </constructor-arg> 10 <constructor-arg type="String" value="male"> 11 </constructor-arg> 12 <constructor-arg type="int" value="18"> 13 </constructor-arg> 14 <constructor-arg type="String" value="i like play football"> 15 </constructor-arg> 16 <constructor-arg> 17 <ref bean="di01"/> 18 </constructor-arg> 19 </bean>
1 package demo.ioc.di; 2 3 public class ConstructDemo01 { 4 5 private String name; 6 private String sex; 7 private int age; 8 private String description; 9 private A01 a01; 10 11 public ConstructDemo01(String name, String sex, int age, String description, A01 a01) { 12 super(); 13 this.name = name; 14 this.sex = sex; 15 this.age = age; 16 this.description = description; 17 this.a01 = a01; 18 } 19 20 public void introduce() { 21 System.out.println("Hello, my name is " + name + ", i'm " + age + " years old."); 22 System.out.println("Description : " + a01.getDescription()); 23 } 24 25 }
如何在構造器注入和 Setter 注入之間進行選擇?
因爲大量的構造器參數多是程序變得笨拙,特別是當前某些屬性是可選的時候。所以一般狀況下,Spring 開發團隊提倡使用 setter 注入。並且 setter DI 在之後的某個時候還能夠將實例從新配置(或從新注入)。
儘管如此,構造器注入由於某些緣由仍是收到了一些人的青睞。一次性將全部依賴注入的作法意味着,在未徹底初始化的狀態下,此對象不會返回給客戶端代碼(或被調用),此外對象也不能再次被從新配置(或從新注入)。
BeanFactory 對於它所管理的 bean 提供兩種注入依賴方式(實際上它也支持同時使用構造器注入和 Setter 方式注入依賴)。須要注入的依賴保存在 BeanDefinition 中,它能根據指定的 PropertyEditor 實現將屬性從一種格式轉換成另一種格式。
處理 bean 依賴關係一般按一下步驟進行:
1)根據定義 bean 的配置(文件)建立並初始化 BeanFactory 實例(大部分的 Spring 用戶使用支持 XML 格式配置文件的 BeanFactory 或 ApplicationContext 實現)。
2)每一個 bean 的依賴將以屬性、構造器參數、或靜態工廠方法參數的形式出現。當這些 bean 被實際建立時,這些依賴也將會提供給該 bean。
3)每一個屬性或構造器參數既能夠是一個實際的值,也能夠是對該容器中另外一個 bean 的引用。
4)每一個指定的屬性構造器參數必須可以被轉換成屬性或構造參數所需的類型。默認狀況下,Spring 會可以以 String 類型提供值轉換成各類內置類型,好比 int、long、String、boolean 等。
Spring 會在容器被建立時驗證容器中每一個 bean 的配置,包括驗證那些 bean 所引用的屬性是否指向一個有效的 bean。然而,在 bean 被實際建立以前,bean 的屬性並不會被設置。對於那些 singleton 類型和被設置爲提早實例化的 bean(好比 ApplicationContext 中的 singleton bean)而言,bean 實例將於容器同時被建立。而另一些 bean 則會在須要的時候被建立,伴隨着 bean 被實際建立,做爲該 bean 的依賴以及依賴 bean 的依賴 bean(以此類推)也將被建立和分配。
循環依賴。當你主要使用構造器注入的方式配置 bean 時,頗有可能會產生循環依賴的狀況。好比說,一個類 A,須要經過構造器注入類 B,而類 B 又須要經過構造器注入類 A。若是爲類 A 和類 B 配置的 bean 被互相注入的話,那麼 Spring IoC 容器將在運行時檢測出循環引用,並拋出 BeanCurrentlyInCreationException 異常。
對於此問題,一個可能的解決方法就是修改源代碼,將構造器注入改成 setter 注入。另外一個解決方法就是徹底放棄使用構造器注入,只是用 setter 注入。
Spring 會在 bean 建立時採起設置屬性和依賴關係(只在須要時建立所依賴的其餘對象)。Spring 容器被正確加載以後,當獲取一個 bean 實例時,若是在建立 bean 或者設置依賴時出現問題,那麼將拋出一個異常。因缺乏或設置了一個無效屬性而致使拋出一個異常的狀況的確是存在的。由於一些配置問題而致使潛在的可見性被延遲,因此在默認狀況下,ApplicationContect 實現中的 bean 採用提早實例化的 singleton 模式。在實際須要以前建立這些 bean 將帶來時間與內存的開銷。而這樣作的好處就是 ApplicationContext 被加載的時候能夠儘早的發現一些配置的問題。不過用戶能夠根據須要採用延遲實例化來替代默認的 singleton 模式。
當協做 bean 被注入到依賴 bean 時,協做 bean 必須在依賴 bean 以前徹底配置好。即協做 bean 實例化完成,相關的依賴也設置完成。
3.2構造器參數的解析
構造器參數將根據類型來進行匹配。若是 bean 定義中的構造器參數類型明確,那麼 bean 定義中的參數順序就是對應構造器參數的順序。
3.2.1構造器參數類型匹配
能夠在構造器參數定義中使用 type 屬性來顯式的指定參數所對應的簡單類型。
1 <bean id="constructDemo02" class="demo.ioc.di.ConstructDemo02"> 2 <constructor-arg type="String" value="Tom"> 3 </constructor-arg> 4 <constructor-arg type="int" value="1"> 5 </constructor-arg> 6 </bean>
1 package demo.ioc.di; 2 3 public class ConstructDemo02 { 4 5 private String s1; 6 private int s2; 7 8 public ConstructDemo02(String s1, int s2) { 9 super(); 10 this.s1 = s1; 11 this.s2 = s2; 12 } 13 14 @Override 15 public String toString() { 16 return "ConstructDemo02 [s1=" + s1 + ", s2=" + s2 + "]"; 17 }; 18 19 }
3.2.2構造器參數索引
經過使用 index 屬性能夠顯式的指定構造器參數出現順序。
1 <bean id="constructDemo03" class="demo.ioc.di.ConstructDemo02"> 2 <constructor-arg index="0" value="Jerry"> 3 </constructor-arg> 4 <constructor-arg index="1" value="100"> 5 </constructor-arg> 6 </bean>
使用 index 屬性除了能夠解決多個簡單類型構造參數形成的模棱兩可的問題以外,還能夠用來解決兩個構造參數類型相同形成的麻煩。index 屬性值從 0 開始。
指定構造器參數索引是使用構造器 IoC 首選的方式。
3.3bean 屬性及構造器參數詳解
3.3.1直接量(基本類型、Strings 類型等)
<value /> 元素經過字符串來指定屬性或構造器參數的值。
3.3.1.1idref 元素
idref 元素用來將容器內其餘 bean 的 id 傳給 <constructor-arg /> 或 <property /> 元素,同時提供錯誤驗證功能。
使用 idref 表級容許容器在部署時,驗證所被引用的 bean 是否存在。
若是被引用的 bean 在同一 XML 文件內,且 bean 名字就是 bean id,那麼可使用 local 屬性。
idref元素容許將容器中另外一個bean的bean id(這是字符串值不是引用)傳遞給一個<property />或<constructor-arg />。在給定的示例中,它清楚地顯示瞭如何將bean id傳遞給另外一個bean,並顯示bean ID。(參考:http://www.roseindia.net/tutorial/spring/spring3/ioc/springidrefelement.html#)
1 package demo.ioc.di2; 2 3 public class FirstBean { 4 5 private String message = null; 6 7 public String getMessage() { 8 return message; 9 } 10 11 public void setMessage(String message) { 12 this.message = message; 13 } 14 15 }
1 package demo.ioc.di2; 2 3 public class AnotherBean { 4 private String amessage = null; 5 6 public String getAmessage() { 7 return amessage; 8 } 9 10 public void setAmessage(String amessage) { 11 this.amessage = amessage; 12 } 13 14 public void display() { 15 System.out.println(amessage); 16 } 17 }
1 package demo.ioc.di2; 2 3 import org.springframework.beans.factory.BeanFactory; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class IDREFMain { 7 public static void main(String[] args) { 8 BeanFactory beanfactory = new ClassPathXmlApplicationContext("applicationContextdi2.xml"); 9 AnotherBean bean = (AnotherBean) beanfactory.getBean("another"); 10 bean.display(); 11 } 12 }
1 <bean id="first" class="demo.ioc.di2.FirstBean"> 2 <property name="message" value="Spring is simple." /> 3 </bean> 4 5 <bean id="another" class="demo.ioc.di2.AnotherBean"> 6 <property name="amessage"> 7 <idref bean="first" /> 8 </property> 9 </bean>
3.3.2引用其餘的 bean
在 <constructor-arg /><property /> 元素內部還可使用 ref 元素。該元素用來將 bean 中指定屬性的值設置爲對容器中的另一個 bean 的引用。如前所述,該引用 bean 將被做爲依賴注入,並且在注入以前會被初始化(若是是 singleton bean 則已被容器初始化)。儘管都是對另一個對象的引用,可是經過 id/name 指向另一個對象卻有三種不一樣的形式,不一樣的形式將決定如何處理做用域及驗證。
第一種形式也是最多見的形式,是經過使用 <ref /> 標記指定 bean 屬性的目標 bean,經過該標籤能夠引用同一容器或父容器內的任何 bean(不管是否在同一 XML 文件中)。XML bean 元素的值既能夠是指定的 bean 的 id也能夠是其 name 值。
1 <ref bean="someBean" />
第二種形式是使用 ref 的 local 屬性指定目標的 bean,它能夠利用 XML 解析器來驗證所引用的 bean 是否存在同一文件中。local 屬性值必須是目標 bean 的 id 屬性值。若是在同一配置文件中沒有找到引用的 bean,XML 解析器將拋出一個異常。若是目標 bean 是在同一文件內,使用 local 方式就是最好的選擇。
1 <ref local="someBean" />
第三種方式是經過使用 ref 的 parent 屬性來引用當前容器的父容器中的 bean。parent 屬性值既能夠是目標 bean 的 id,也能夠是 name 屬性值。並且目標 bean 必須在當前容器的父容器中。使用 parent 屬性的主要用途是爲了用某個與父容器中的 bean 同名的代理來包裝父容器中的一個 bean。parent 屬性的使用並不常見。
3.3.3內部 bean
所謂的內部 bean 是指在一個 bean 的 <property /> 或 <constructor-arg /> 元素中使用 <bean /> 元素定義的 bean。內部 bean 定義不須要有 id 或 name 屬性,即便指定 id 或 name 屬性值也將會被容器忽略。
內部 bean 中的 singleton 標記 及 id 或 name 屬性將被忽略。內部 bean 老是匿名的且他們老是 prototype 模式的。同時將內部 bean 注入到包含該內部 bean 以外的 bean 是不可能的。
實例:http://www.yiibai.com/spring/spring-inner-bean-examples.html
注入的時候注意構造函數。Setter 注入的話別忘了默認的構造函數。
3.3.4集合
經過 <list />、<set />、<map /> 及 <props /> 元素能夠定義和設置與 Java Collection 類型對應 List、Set、Map 及 Properties 的值。
實例:http://blog.csdn.net/thc1987/article/details/5790792
3.3.4.1集合合併
從 2.0 開始,Spring IoC 容器將支持集合的合併。這樣咱們能夠定義 parent-style 和 child-style 的 <list />、<set />、<map /> 及 <props /> 元素,子集合的值從其父集合繼承和覆蓋二來;也就是說,父子集合元素合併後的值就是子集合中的最終結果,並且子集合中的元素值將覆蓋父集合中對應的值。
1 <bean id="father" abstract="true" class="demo.ioc.combine.Father"> 2 <property name="list"> 3 <list> 4 <value>test1</value> 5 <value>test2</value> 6 <value>test3</value> 7 </list> 8 </property> 9 </bean> 10 11 <bean id="son" parent="father" class="demo.ioc.combine.Son"> 12 <property name="list" > 13 <list merge="true"> 14 <value>host1</value> 15 <value>host2</value> 16 </list> 17 </property> 18 </bean>
1 package demo.ioc.combine; 2 3 import java.util.List; 4 import java.util.Map; 5 6 public class Father { 7 8 private List<String> list; 9 10 private Map<Integer, String> map; 11 12 public List<String> getList() { 13 return list; 14 } 15 16 public void setList(List<String> list) { 17 this.list = list; 18 } 19 20 public Map<Integer, String> getMap() { 21 return map; 22 } 23 24 public void setMap(Map<Integer, String> map) { 25 this.map = map; 26 } 27 28 }
1 package demo.ioc.combine; 2 3 import java.util.List; 4 import java.util.Map; 5 6 import org.springframework.context.ApplicationContext; 7 import org.springframework.context.support.ClassPathXmlApplicationContext; 8 9 public class Son extends Father { 10 11 private List<String> list; 12 13 public List<String> getList() { 14 return list; 15 } 16 17 public void setList(List<String> list) { 18 this.list = list; 19 } 20 21 public void print() { 22 if (list != null) { 23 for (String s : list) { 24 System.out.println(s); 25 } 26 } 27 } 28 29 public static void main(String[] args) { 30 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextCombine.xml"); 31 Son son = (Son) context.getBean("son"); 32 son.print(); 33 } 34 }
參考:http://blog.csdn.net/opnmzxcvb/article/details/4971799
http://liyixing1.iteye.com/blog/1036520
對於 <list />、<map /> 及 <set /> 集合將從父 <props /> 繼承全部屬性元素。同時子 bean 的suppory 值將覆蓋父集合的相應值。
對於 <list /> ,父 bean 的列表內容將排在子 bean 列表內容的前面。對於 Map、Set 及 Properties 集合類型沒有順序的概念,所以做爲相關的 Map、Set 及 Properties 實現基礎的集合類型在容器內部沒有排序的語義。
不一樣的集合類型是不能合併的,不然會拋出相應的 Exception。merge 屬性必須在繼承的子 bean 中定義,而在父 bean 的集合屬性上指定的 merge 屬性將被忽略。
3.3.4.2強類型集合
將 value 元素值轉換爲相應的泛型類型的值。
3.3.5Nulls
<null /> 用於處理 null 值。Spring會把屬性的空參數當作空字符串處理。而 null 值可使用 <null /> 元素來表示。
3.3.6XML-based configura metada shortcus
針對常見的 value 值或 bean 的引用,Spring 提供了簡化格式用於替代 <value /> 和 <ref /> 元素。<property />、<constructor-arg /> 及 <entry /> 元素都支持 value 屬性,他能夠替代內嵌的 <value /> 元素。
3.3.7組合屬性名稱
當設置 bean 的組合屬性時,除了最後一個屬性外,只要其餘屬性值不爲 null,組合或嵌套屬性名是徹底合法的。
組合屬性在 bean 被構造後必須非空,不然會拋出長異常。
實例:http://blog.csdn.net/confirmaname/article/details/9362379
3.4使用 depends-on
一個 bean 對另外一個 bean 的依賴最簡單的作法就是將一個 bean 設置爲另一個 bean 的屬性。在 xml 配置文件中最多見的就是使用 <ref /> 元素。有時候它還有另一種變體,若是一個 bean 能感知 IoC 容器,只要給出他所依賴的 id,那麼久能夠經過編程的方式從容器中取得它所依賴的對象。
不管採用哪種方法,被依賴 bean 將在依賴 bean 以前被適當的初始化。
在少數狀況下,有時候 bean 之間的依賴關係並非那麼的直接。depends-on 屬性能夠用於當前 bean 初始化以前顯式強制一個或多個 bean 被初始化。
實例:http://blog.csdn.net/pzw_0612/article/details/48021509
3.3.5延遲初始化 bean
ApplicationContext 實現的默認行爲就是在啓動時將全部 singleton bean 提早進行實例化。提早實例化意味着做爲初始化過程的一部分,ApplicationContext 實例會建立並配置全部的 singleton bean。
若是不想讓一個 singleton bean 在 ApplicationContext 實如今初始化時被提早實例化,那麼能夠將 bean 設置爲延遲實例化。一個延遲初始化 bean 將告訴 IoC 容器是在啓動時仍是在第一次被用到時實例化。
在 XML 配置文件中,延遲初始化將經過 <bean /> 元素中的 lazy-init 屬性來進行控制。
若是一個 bean 被設置爲延遲初始化,而另外一個非延遲初始化的 singleton bean 依賴於它,那麼當 ApplicationContext 提早實例化 singleton bean 時,它必須也確保全部上述 singleton 依賴也被預先初始化,固然也包括設置爲延遲實例化的 bean。
在容器層次中經過在 <beans /> 元素上使用 'default-lazy-init' 屬性來控制延遲初始化也是可能的。
1 <beans default-lazy-init="true"> 2 ... 3 <beans>
3.3.6自動裝配(autowire)協做者
實例:http://blog.csdn.net/fengyun111999/article/details/6320486
Spring IoC 容器能夠自動裝配相互協做 bean 之間的關聯關係。所以,若是可能的話,能夠自動讓 Spring 經過檢查 BeanFactory 中的內容,來替咱們指定 bean 的協做者。因爲 autowire 能夠針對單個 bean 進行設置,所以可讓有些 bean 使用 autowire,有些 bean 不採用。autowire 的方便之處在減小或者消除屬性或構造參數的設置,這樣能夠給咱們的配置文件減減肥。在 xml 配置文件中,autowire 一共有五種類型,能夠在 <bean /> 元素中使用 autowire 屬性指定。
模式 |
說明 |
no |
(默認)不採用autowire機制.。這種狀況,當咱們須要使用依賴注入,只能用<ref/>標籤。 |
byName |
經過屬性的名稱自動裝配(注入)。Spring會在容器中查找名稱與bean屬性名稱一致的bean,並自動注入到bean屬性中。固然bean的屬性須要有setter方法。例如:bean A有個屬性master,master的setter方法就是setMaster,A設置了autowire="byName",那麼Spring就會在容器中查找名爲master的bean經過setMaster方法注入到A中。 |
byType |
經過類型自動裝配(注入)。Spring會在容器中查找類(Class)與bean屬性類一致的bean,並自動注入到bean屬性中,若是容器中包含多個這個類型的bean,Spring將拋出異常。若是沒有找到這個類型的bean,那麼注入動做將不會執行。 |
constructor |
相似於byType,可是是經過構造函數的參數類型來匹配。假設bean A有構造函數A(B b, C c),那麼Spring會在容器中查找類型爲B和C的bean經過構造函數A(B b, C c)注入到A中。與byType同樣,若是存在多個bean類型爲B或者C,則會拋出異常。但時與byType不一樣的是,若是在容器中找不到匹配的類的bean,將拋出異常,由於Spring沒法調用構造函數實例化這個bean。 |
default |
採用父級標籤(即beans的default-autowire屬性)的配置。 |
若是直接使用 property 和 consturctor-arg 注入依賴的話,那麼將老是覆蓋自動裝配。並且目前也不支持簡單類型的自動裝配,這裏所說的簡單類型包括基本類型、String、Class 以及簡單類型的數組。自動裝配還能夠與依賴檢查結合使用,這樣依賴檢查將在自動裝配完成以後被執行。
優勢:自動裝配能顯著減小配置的數量。不過,採用 bean 模板也能夠達到一樣的目的。
自動裝配可使配置與 java 代碼同步更新。
缺點:Spring 會盡可能避免在裝配不明確的時候進行猜想,由於裝配不明確可能出現難以預料的結果,並且 Spring 所管理的對象之間的關聯關係也再也不能清晰的進行文檔化。
對於那些根據 Spring 配置文件生成文檔的工具來講,自動裝配將會使這些工具無法生成依賴信息。
若是採用 by type 方式自動裝配,那麼容器中類型與自動裝配 bean 的屬性或者構造函數參數類型一致的 bean 只能有一個,若是配置可能存在多個這樣的 bean,那麼就要考慮採用顯示裝配了。
3.6.1設置 bean 使自動裝配失效
當採用 xml 格式配置 bean 時,<bean /> 元素的 autowire-candidate 屬性可被設爲 false,這樣容器在查找自動裝配對象時將不考慮該 bean。
對於那些歷來就不會被其餘 bean 採用自動裝配的方式來注入的 bean 而言,這是有用而。不過這並不意味着被排除的 bean 本身就不能使用自動裝配來注入其餘 bean,他是能夠的,或者更準確的說,應該是他不會被考慮做爲其餘 bean 自動裝配的候選者。
1 <bean id="a" class="demo.ioc.autowire.ClassA" autowire-candidate="false"> 2 <property name="stringa" value="testa"></property> 3 <property name="stringb" value="testb"></property> 4 <property name="a" value="10000"></property> 5 </bean> 6 7 <bean id="b" class="demo.ioc.autowire.ClassB" autowire="byType"></bean>
3.7依賴檢查
Spring 除了能對容器中 bean 的依賴設置進行檢查外。還能夠檢查 bean 定義中實際屬性值的設置,固然也包括採用自動裝配方式設置屬性值的檢查。
當須要確保 bean 的全部屬性值(或者屬性類型)被正確設置的時候,那麼這個功能會很是有用。固然,在不少狀況下,bean 類的某些屬性會具備默認值,或者有些屬性並不會在全部場景下使用,所以這項功能會存在必定的侷限性。就像自動裝配同樣,依賴檢查也能夠針對每個 bean 進行設置。依賴檢查默認爲 none,他有幾種不一樣的使用模式,在 xml 配置文件中,能夠在 bean 定義中爲 dependency-check 屬性使用如下幾種值:
模式 | 說明 |
none | 沒有依賴檢查,若是 bean 的屬性沒有值的話能夠不用設置 |
simple | 對於原始類型及集合(除協做者外的一切東西)執行依賴檢查 |
object | 僅對協做者執行依賴檢查 |
all | 對協做者,原始類型及集合執行依賴檢查 |
資料:http://biancheng.dnbcw.net/linux/413491.html
Spring 3.0 已取消該屬性。
在 spring 3 中替代 dependency-check 有4條建議:
3.8方法注入
在大部分狀況下,容器中的 bean 都是 singleton 類型的。若是一個 singleton bean 要引用另一個 singleton bean,或者一個非 singleton bean 要引用另一個非 singleton bean時,一般狀況下將一個 bean 定義爲另外一個 bean 的 property 值就能夠了。不過對於具備不一樣生命週期的 bean 來講這樣作就會有問題了,好比在調用一個 singleton 類型 bean A 的某個方法時,須要引用另外一個非 singleton(prototype)類型的 bean B,對於 bean A 來講,容器只會建立一次,這樣就無法在須要的時候每次讓容器爲 bean A 提供一個新的的 bean B 實例。
對於上面的問題Spring提供了三種解決方案:
實例:http://flysnow.iteye.com/blog/733785
4bean 的做用域
Spring 支持五種做用域(其中有三種只能用在基於 web 的 Spring ApplicationContext)
內置支持的做用域分列以下:
在每一個Spring IoC容器中一個bean定義對應一個對象實例。 |
|
一個bean定義對應多個對象實例。 |
|
在一次HTTP請求中,一個bean定義對應一個實例;即每次HTTP請求將會有各自的bean實例,它們依據某個bean定義建立而成。該做用域僅在基於web的Spring ApplicationContext情形下有效。 |
|
在一個HTTP Session中,一個bean定義對應一個實例。該做用域僅在基於web的Spring ApplicationContext情形下有效。 |
|
在一個全局的HTTP Session中,一個bean定義對應一個實例。典型狀況下,僅在使用portlet context的時候有效。該做用域僅在基於web的Spring ApplicationContext情形下有效。 |
4.1Singleton做用域
當一個 bean 的做用域爲 singleton,那麼 Spring IoC 容器中只會存在一個共享的 bean 實例,而且全部對 bean 的請求,只要 id 與該 bean定義相匹配,則只會返回 bean 的同一實例。Singleton 做用域是 Spring 中的缺省做用域。
1 <bean id=".." class=".." scope="singleton"> 2 ... 3 </bean>
4.2Prototype做用域
Prototype 做用域的 bean 會致使在每次對該 bean 請求時都會建立一個新的 bean 實例。根據經驗,對全部有狀態的 bean 應該使用 prototype 做用域,而對無狀態的 bean 則應該使用 singleton 做用域。
1 <bean id=".." class=".." scope="prototype"> 2 ... 3 </bean>
對於 prototype 做用域的 bean,有一點很是重要,那就是 Spring 不能對一個 prototype bean 的整個生命週期負責:容器在初始化、配置、裝飾或者是裝配玩一個 prototype 實例後,將它交給客戶端,隨後就對該 prototype 實例漠不關心了。無論何種做用域,容器都會調用全部對象的初始化生命週期回調方法,而對 prototype 而言,任何配置好的析構生命週期毀掉方法都不會被調用。清除 prototype 做用域的對象並釋聽任何 prototype bean 所持有的昂貴資源,都是客戶端代碼的職責。(讓 Spring 容器釋放被 singleton 做用域 bean 佔用資源的一種可行方式是,經過使用 bean 的後置處理器,該處理器持有要被清除的 bean 的引用。)
4.3其餘做用域
其餘做用域,即 request、session 以及 global session 僅在基於 web 的應用中使用。
下面介紹的做用域僅僅在使用基於 web 的 spring applicationcontext 實現(如 xmlwebapplicationcontext)時有用。若是在普通的 spring ioc 容器中,好比像 xmlbeanfactory 或 classpathxmlapplicationcontext,嘗試使用這些做用域,將會獲得一個 illegalstateexception 異常。
4.3.1初始化 web 配置
要使用 request、session 和 global session 做用域的 bean(即具備 web 做用域的 bean),在開始設置 bean 定義以前,還要作少許的初始配置。
若是使用的是 servlet 2.4 及以上的 web 容器,那麼須要在 web 應用的 xml 聲明文件 web.xml 中增長下述 ContextListener
1 <web-app> 2 ... 3 <listener> 4 <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> 5 </listener> 6 ... 7 </web-app>
若是使用的是早起版本的 web 容器(Servlet 2.4 之前),那麼須要使用一個 javax.servlet.Filter 的實現
1 <web-app> 2 ... 3 <filter> 4 <filter-name>requestContextFilter</filter-name> 5 <filter-class>org.springframework.web.filter.RequestFilter</filter-class> 6 </filter> 7 <filter-mapping> 8 <filter-name>requestContextFilter</filter-name> 9 <url-pattern>/*</url-pattern> 10 </filter-mapping> 11 ... 12 </web-app>
RequestContextListener 和 RequestContextFilter 兩個類作的都是一樣的工做:將 HTTP request 對象綁定到爲該請求提供服務的 Thread。這使得具備 requset 和 session 做用域的 bean 可以在後面的調用鏈中被訪問到。
4.3.2Request 做用域
5定製 bean 特性
5.1Lifecycle 接口
Spring 提供了幾個標誌接口,這些接口用來改變容器中 bean 的行爲;它們包括 InitializingBean 和 DisposableBean。實現這兩個接口的 bean 在初始化和析構時容器會調用前者的 afterPropertiesSet() 方法,以及後者的 destory() 方法。
Spring 在內部使用 BeanPostProcessor 實現來處理它能找到的任何標誌接口並調用相應的方法。若是須要自定義特性或者生命週期行爲,能夠實現本身的 BeanPostProcessor。
5.1.1初始化回調
實現 org.springframework.beans.factory.InitializingBean 接口容許容器在設置好 bean 的全部必要屬性後,執行初始化事宜。InitializingBean 接口僅指定了一個方法:
1 void afterPropertiesSet() throws Exception;
一般,要避免使用 InitializingBean 接口,並且不鼓勵使用該接口,由於這樣會將代碼和 spring 耦合,能夠在 Bean 定義中指定一個普通的初始化方法,即在 xml 配置文件中經過指定 init-method 屬性來完成。
1 package demo.ioc.callback; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 public class A { 7 8 private String string; 9 private int i; 10 11 public String getString() { 12 return string; 13 } 14 public void setString(String string) { 15 this.string = string; 16 } 17 public int getI() { 18 return i; 19 } 20 public void setI(int i) { 21 this.i = i; 22 } 23 24 public void init() { 25 System.out.println("init"); 26 } 27 28 public static void main(String[] args) { 29 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextdiCallback.xml"); 30 // A a = (A) context.getBean("a"); 31 } 32 }
1 package demo.ioc.callback; 2 3 import org.springframework.beans.factory.InitializingBean; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 public class A2 implements InitializingBean { 8 9 private String string; 10 private int i; 11 12 public String getString() { 13 return string; 14 } 15 public void setString(String string) { 16 this.string = string; 17 } 18 public int getI() { 19 return i; 20 } 21 public void setI(int i) { 22 this.i = i; 23 } 24 25 public void init() { 26 System.out.println("init"); 27 } 28 29 public static void main(String[] args) { 30 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextdiCallback.xml"); 31 // A a = (A) context.getBean("a"); 32 } 33 public void afterPropertiesSet() throws Exception { 34 // TODO Auto-generated method stub 35 System.out.println("init--"); 36 37 } 38 }
1 <bean id="a" class="demo.ioc.callback.A" init-method="init"> 2 </bean> 3 4 <bean id="a2" class="demo.ioc.callback.A2"> 5 </bean>
5.1.2析構回調
實現 org.springframework.beans.factory.DisposableBean 接口的 bean 容許在容器銷燬該 bean 的時候得到一次回調。DisposableBean 接口也只規定了一個方法:
1 void destory() throws Exception;
一般,要避免使用 DisposableBean 標誌接口,能夠在 bean 定義中指定一個普通的析構方法,即在 xml 配置文件中經過 destory-method 屬性來完成。
5.1.2.1缺省的初始化和析構方法
生命週期回調方法的名稱最好在一個項目範圍內標準化。
能夠將 Spring 容器配置成在每一個 bean 上查找實現指定好的初始化和析構回調方法名稱。這樣就能夠簡化 bean 定義,好比根據約定將初始化回調命名爲 init(),而後在基於 xml 的配置中,就能夠省略 init-method="init" 配置,而 Spring IoC 容器將會在 bean 被建立的時候調用該方法。
1 <beans default-init-method="init"> 2 ... 3 </beans>
該屬性的出現意味着 Spring IoC 容器會把 bean 上名爲 init 的方法識別爲初始化方法回調,而且當 bean 被建立和裝配的時候,若是 bean 類具備這樣的方法,他將會在適當的時候被調用。
相似的,配置析構方法回調是在頂層 <beans /> 元素上使用 default-destory-method 屬性。
若是實際的回調方法與默認的命名約定不一樣,那麼能夠經過在 <bean /> 元素上使用 init-method 和 destory-method 屬性指定方法名來覆蓋缺省設置。
5.1.2.2在非 web 應用中優雅的關閉 spring ioc 容器
在基於 web 的 ApplicationContext 實現中已有相應的代碼來處理關閉 web 應用時如何恰當地關閉 Spring IoC 容器。
若是在非 web 應用的環境下使用 Spring 的 IoC 容器,則須要在 JVM 裏註冊一個關閉鉤子(shutdown hook)。爲了註冊關閉鉤子,須要簡單地調用在 AbstractApplicationContext 實現中的 registerShutdownHook() 方法便可。
1 AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 2 context.registerShutdownHook();
5.2瞭解本身
5.2.1BeanFactoryAware
對於實現了 org.springframework.beans.factory.BeanFactoryAware接口的類,當它被 BeanFactory 建立後,他會擁有一個指向建立它的 BeanFactory 的引用。
1 public interface BeanFactoryAware { 2 3 void setBeanFactory(BeanFactory beanFactory) throws BeansException; 4 5 }
這樣 bean 能夠以編程的方式操控建立他們的 BeanFactory,固然咱們能夠將引用的 BeanFactory 造型爲已知的子類型來得到更多的功能。它主要用於經過編程來取得 BeanFactory 所管理的其餘 bean。雖然在有些場景下這個功能頗有用,可是通常來講應該儘可能避免使用,由於這樣將使代碼與 Spring 耦合在一塊兒,並且也有違反控制的原則(協做者應該做爲屬性提供給 bean)。
與 BeanFactoryAware 等效的另外一種選擇是使用 org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean。不過該方法依然沒有下降與 Spring 的耦合,可是它並無像 BeanFactoryAware 那樣,違反 IoC 原則。
ObjectFactoryCreatingFactoryBean 是 FactoryBean 的一個實現,它返回一個執行工廠對象的引用,該對象將執行 bean 的查找。OObjectFactoryCreatingFactoryBean 類實現了 BeanFactoryAware 接口;被實際注入到客戶端 bean 的是 ObjectFactory 接口的一個實例。這是 Spring 提供的一個接口(於是依舊沒有徹底與 Spring 解耦),客戶端可使用 ObjectFactory 的 getObject() 方法來查找 bean。你要作的所有事情就是給 ObjectFactoryCreatingFactoryBean 提供待查找 bean 的名字。
5.2.2BeanNameAware
假如 bean 實現了 org.springframework.beans.factory.BeanNameAware 接口並被部署在一個 BeanFactory 中,BeanFactory 會經過該接口的 setBeanName() 方法以告知其被部署時的 bean id。在 bean 屬性被設置完成以後,在向 InitializingBean 的 afterPropertiesSet 或是自定義 init-method 這樣的初始化回調執行以前,該接口的回調方法會被調用。
6bean 定義的繼承
當使用基於 XML 的配置元數據時,給 parent 屬性指定值,意味着子 bean 定義的聲明。
若是子 bean 定義沒有指定 class 屬性,它將使用父 bean 定義的 class 屬性,固然也能夠覆蓋它。在後面一種狀況下,子 bean 的 class 屬性值必須同父 bean 兼容,也就是它必須接受父 bean 的屬性值。
一個子 bean 定義能夠從 bean 繼承構造器參數值、屬性值以及覆蓋父 bean 的方法,而且能夠有選擇地增長新的值。若是制定了 init-method,desroty-method 或 static factory-method,他們就會覆蓋父 bean 相應的設置。
剩餘的設置老是從子 bean 定義處獲得:依賴、自動裝配模式、依賴檢查、singleton、做用域和延遲初始愛護。
抽象 bean 定義可做爲子 bean 定義的模板。若是嘗試單獨使用這樣的父 bean,將會致使錯誤;一樣,容器內部的 preInstantiateSingletons() 方法會徹底忽略 abstract 的 bean 定義。
默認狀況下,ApplicationContext(不是 BeanFactory)會預實例化全部 singleton 的bean。所以很重要的一點是:若是隻想把一個父 bean 定義當作模板使用,而他又制定了 class 屬性,那麼就得將 abstract 屬性設置爲 true,不然應用上下文將會預實例化抽象 bean。
1 <bean id="currency" abstract="true"> 2 <property name="name" value="Tom"></property> 3 <property name="age" value="26"></property> 4 <property name="sex" value="male"></property> 5 </bean> 6 7 <bean id="son" parent="currency" class="demo.ioc.inherit.Son"> 8 <property name="favourite" value="play games"></property> 9 </bean>
7容器擴展點
Spring 框架的 IoC容器被設計爲可擴展的。一般咱們並不須要子類化各個 BeanFactory 或 ApplicationContext 實現類。而經過 plugin 各類集成接口實現來進行擴展。
7.1用 BeanPostProcessor 定製 bean
BeanPostProcessor 定義了幾個回調方法,實現該接口可提供自定義(或默認地來覆蓋容器)的實例化邏輯、依賴解析邏輯等。若是想在 Spring 容器完成 bean 的實例化、配置和其餘的初始化後執行一些自定義邏輯,你能夠插入一個或多個的 BeanPostProcessor 實現。
若是配置了多個 BeanPostProcessor ,那麼能夠經過設置 order 屬性來控制 BeanPostProcessor 的執行次序(僅當 BeanPostProcessor 實現了 Ordered 接口時,才能夠設置此屬性,所以在編寫本身的 BeanPostProcessor 實現時,就得考慮是否須要實現 Ordered 接口)。
實例:http://winneryj.iteye.com/blog/307736
7.2用 BeanFactoryPostProcessor 定製配置元數據
這個接口跟 BeanPostProcessor 相似,BeanFactoryPostProcessor 能夠對 bean 的定義進行處理。也就是說 Spring IoC 容器容許 BeanFactroyPostProcessor 在容器實際實例化任何其餘的 bean 以前讀取配置與數據,並有可能修改它。
實例:http://blog.csdn.net/caihaijiang/article/details/35552859
若是想改變實際的 bean 實例,那麼最好使用 BeanPostProcessor。
BeanFactoryPostProcessor 的做用域範圍是容器級的。它只和所使用的容器有關。若是在容器中定義一個 BeanFactoryPostProcessor,它僅僅對此容器中的 bean 進行後置處理。BeanFactoryPostProcessor 不會對定義在另外一個容器中的 bean 進行後置處理,即便這兩個容器都是在同一層次上。
不要將 BeanFactoryPostProcessors 標記爲延遲加載。不然 Spring 容器將不會註冊他們,自定義邏輯就沒法實現。若是在 <beans /> 元素的定義中使用了 default-lazy-init 屬性,請確信各個 BeanFactoryPostProcessor 標記爲 lazy-init="false"