Spring 不但能夠經過 <ref> 引用另外一個 Bean,創建起 Bean 和 Bean 之間的依賴關係,<bean> 元素標籤之間也能夠創建相似的關係,完成一些特殊的功能。數據庫
1.繼承數組
OOP思想告訴咱們,若是多個類擁有相同的方法和屬性,則能夠引入一個父類,在父類中定義這些類共同的方法和屬性,以消除重複的代碼。一樣,若是多個 <bean> 存在相同的配置信息,則 Spring 容許定義一個父<bean>,子<bean>將自動繼承父<bean>的配置信息。緩存
下面經過一個實例,對使用和未使用父子<bean>的配置進行比較,從中看出父子<bean>給配置帶來的便利性,以下所示。優化
未使用父子<bean>的配置spa
<bean id="car1" class="com.smart.tagdepend.Car" p:brand="紅旗CA72" p:price="2000.00" p:color="黑色" /> <bean id="car2" class="com.smart.tagdepend.Car" p:brand="紅旗CA72" p:price="2000.00" p:color="紅色" />
上面代碼配置了兩個 car Bean,咱們發現這兩個 Bean 的配置存在大量的重複信息。事實上,兩者除了 color 屬性配置值不同外,其餘配置信息都相同。經過父子<bean>的繼承關係就能夠很好地消除這種重複的配置信息以下所示。code
使用父子<bean>的配置xml
<!-- ①定義爲抽象<bean> --> <bean id="abstractCar" class="com.smart.tagdepend.Car" p:brand="紅旗CA72" p:price="2000.00" p:color="黑色" abstract="true"/> <!-- ②繼承於abstractCar --> <bean id="car3" parent="abstractCar"> <property name="color" value="紅色"/> </bean> <!-- ③繼承於abstractCar --> <bean id="car4" parent="abstractCar" > <property name="color" value="白色"/> </bean>
car3 和 car4 這兩個 <bean> 都繼承於 abstractCar 的 <bean>,Spring 會將父<bean>的配置信息傳遞給子<bean>。若是子<bean>提供了父<bean>已有的配置信息,那麼子<bean>的配置信息將覆蓋父<bean>的配置信息。blog
父<bean>的主要功能是簡化子<bean>的配置,因此通常聲明爲 abstract="true",表示這個<bean>不實例化爲一個對應的Bean。若是用戶沒有指定 abstract="true",則 Spring IOC容器會實例化一個名爲 abstractCar 的 Bean。繼承
2.依賴
通常狀況下,可使用 <ref> 元素標籤創建對其餘 Bean 的依賴關係,Spring 負責管理這些 Bean 的關係。當實例化一個 Bean 時,Spring 保證該 Bean 所依賴的其餘 Bean 已經初始化。內存
但在某些狀況下,這種 Bean 之間的依賴關係並不那麼明顯。下面舉一個例子。「小春論壇」擁有不少系統參數(如會話過時時間、緩存更新時間等),這些系統參數用於控制系統的運行邏輯。咱們用一個 SystemSettings 類表示這些系統參數。
public class SystemSettings { public static int SESSION_TIMEOUT = 30; public static int REFRESH_CYCLE = 60; }
在 SystemSettings 類中爲每一個系統參數提供了默認值,但一個靈活的論壇必須提供一個管理後臺,在管理後臺中能夠調整這些系統參數並保存到後臺數據庫中,在系統啓動時,初始化程序從數據庫後臺加載這些系統參數的配置值以覆蓋默認值。
public class SysInit { public SysInit(){ System.out.println("SysInit"); //模擬從數據庫中加載系統設置信息 SystemSettings.REFRESH_CYCLE = 100; SystemSettings.SESSION_TIMEOUT = 10; } }
假設論壇有一個緩存刷新管理器,它須要根據系統參數 SystemSettings.REFRESH CYCLE建立緩存刷新定時任務。
public class CacheManager { public CacheManager(){ Timer timer = new Timer(); TimerTask cacheTask = new CacheTask(); timer.schedule(cacheTask,0,SystemSettings.REFRESH_CYCLE*1000); } }
在以上實例中,CacheManager 依賴於 SystemSettings,而 SystemSettings 的值由 Syslnit 負責初始化。雖然 CacheManager 不直接依賴於 Syslnit,但從邏輯上看,CacheManager 但願在 Syslnit 加載並完成系統參數設置後再啓動,以免調用不到真實的系統參數值。若是這3個 Bean 都在 Spring 配置文件中定義,那麼如何保證 Syslnit 在 CacheManager 以前進行初始化呢?
Spring 容許用戶經過 depends-on 屬性顯式指定 Bean 前置依賴的 Bean,前置依賴的 Bean 會在本 Bean 實例化以前建立好。
<!-- <bean>的依賴 --> <bean id="cacheManager" class="com.smart.tagdepend.CacheManager" depends-on="sysInit" /> <bean id="sysInit" class="com.smart.tagdepend.SysInit" />
經過 depends-on 屬性將 syslnit 指定爲 manager 前置依賴的 Bean,這樣就能夠保證 managerBean 在實例化並運行時所引用的系統參數是最新的設置值,而非 SystemSettings 類中的默認值。若是前置依賴於多個 Bean,則能夠經過逗號、空格或分號的方式建立 Bean 的名稱。
3.引用
假設一個<bean>要引用另外一個<bean>的id屬性值,則能夠直接使用如下配置方式:
<!-- <bean>引用 --> <bean id="car" class="com.smart.tagdepend.Car"/> ① <bean id="boss" class="com.smart.tagdepend.Boss" > ② <property name="carId" > <value>car</value> </property> </bean>
假設但願將 boss Bean 的 carld 設置爲①處 <bean> 的 id 值,雖然能夠經過②處的方式以字面值的形式進行設置,但兩者之間並無創建引用關係。通常狀況下,在一個 Bean 中引用另外一個 Bean 的 id 是但願在運行期經過 getBean(beanName) 方法獲取對應的 Bean。因爲 Spring 並不會在容器啓動時對屬性配置值進行特殊檢查,所以,即便編寫錯誤,也須要等到具體調用時纔會發現。
Spring 爲此提供了一個 <idref> 元素標籤,能夠經過 <idref> 引用另外一個 <bean> 的名字。在容器啓動時,Spring 負責檢查引用關係的正確性,這樣就能夠提早發現錯誤。所以,下面的配置是推薦的優化方案:
<bean id="car" class="com.smart.tagdepend.Car"/> ① <bean id="boss" class="com.smart.tagdepend.Boss" > ② <idref bean="car"/> </property> </bean>
假設②處因爲配置錯誤,誤將 <idref bean="car"/> 寫爲 <idref bean="cat"/>,那麼 Spring 容器在啓動時,將會拋出 BeanDefinitionStoreException,提示容器中沒有名爲 cat 的 Bean
若是引用者和被引用者的 <bean> 位於同一個XML配置文件中,則可使用 <idref local="car"> 的配置方式,這時IDE的XML分析器就能夠在開發期發現引用錯誤了。
整合多個配置文件
對於一個大型應用來講,可能存在多個 XML 配置文件,在啓動 Spring 容器時,能夠經過一個 String 數組指定這些配置文件。Spring 還容許經過 <import> 將多個配置文件引入到一個文件中,進行配置文件的集成。這樣,在啓動 Spring 容器時,僅需指定這個合併好的配置文件便可。
<import resource="classpath:com/smart/impt/beans1.xml"/> ① <bean id="boss1" class="com.smart.fb.Boss" p:name="John" p:car-ref="car1"/> <bean id="boss2" class="com.smart.fb.Boss" p:name="John" p:car-ref="car2"/>
假設已經在 beans1.xml 中配置了 car1 和 car2 的 Bean,在①處經過 <import> 的 resource 屬性引入 beans1.xml,beans2.xml 就擁有了完整的配置信息,Spring 容器僅需經過 beans2.xml 就能夠加載全部的配置信息。
須要指出的是,若是一個配置文件 a.xml 定義的 <bean> 引用了另外一個配置文件 b.xml 定義的 <bean>,那麼並不必定須要經過 <import> 引入 b.xml,只需在啓動 Spring 容器時,a.xml 和 b.xml 都在配置文件列表中便可。區別在於,若是 a.xml 採用 import 引入了 b.xml,至關於 a.xml 一個文件就包含了 a.xml 和 b.xml 兩個文件的內容,所以 Spring 容器啓動時僅需加載 a.xml 便可:不然就須要在啓動 Spring 容器時,同時加載 a.xml 和 b.xml 配置文件,以便在內存中對 a.xml 和 b.xml 進行合併。
一個 XML 配置文件能夠經過 <import> 組合多個外部的配置文件,resource 屬性支持 Spring 標準的資源路徑。