在本章中,咱們將介紹如下內容:java
咱們在第一章和第二章中看到,應用程序上下文 XML 文件中的 bean 定義指定了 bean 類及其依賴項的徹底限定名稱。在某些場景下,爲了使 bean 定義不那麼冗長,你可能但願 bean 定義從另外一個 bean 定義繼承配置信息。下面介紹 MyBank 應用中這樣的一個場景。spring
在上一章中,咱們瞭解到 MyBank 應用經過 DAO 來訪問數據庫。假設 MyBank 應用定義了一個能夠與數據庫交互的 DatabaseOperations 類,所以 MyBank 應用中的全部 DAO 都依賴於 DatabaseOperations 類來執行數據庫操做,以下圖所示。數據庫
上圖展現了 FixedDepositDao 和 PersonalBankingDao 類依賴於 DatabaseOperations 類。如下應用程序上下文 XML 文件展現了這些類的 bean 定義。apache
<bean id="databaseOperations" class="sample.spring.chapter01.bankapp.utils.DatabaseOperations"></bean> <bean id="personalBankingDao" class="sample.spring.chapter01.bankapp.dao.PersonalBankingDaoImpl"> <property name="databaseOperations" ref="databaseOperations" /> </bean> <bean id="fixedDepositDao" class="sample.spring.chapter01.bankapp.dao.FixedDepositDaoImpl"> <property name="databaseOperations" ref="databaseOperations" /> </bean>
上面 xml 中,personalBankingDao 和 fixedDepositDao bean 定義都使用 databaseOperations 屬性來引用 DatabaseOperations 實例。這意味着 PersonalBankingDaoImpl 和 FixedDepositDaoImpl 類都定義了一個 setDatabaseOperations 方法,以容許 Spring 容器注入 DatabaseOperations 實例。app
若是應用程序中的 多個 bean 共享一組公共的配置 (屬性、構造函數參數等),則能夠建立一個 bean 定義,做爲其餘 bean 定義的父定義。在 personalBankingDao 和 fixedDepositDao bean定義中,公共的配置是 databaseOperations 屬性。下面展現了 personalBankingDao 和 fixedDepositDao bean 定義如何從父 bean 定義繼承 databaseOperations 屬性。dom
<bean id="databaseOperations" class="sample.spring.chapter03.bankapp.utils.DatabaseOperations"></bean> <bean id="daoTemplate" abstract="true"> <property name="databaseOperations" ref="databaseOperations" /> </bean> <bean id="fixedDepositDao" parent="daoTemplate" class="sample.spring.chapter03.bankapp.dao.FixedDepositDaoImpl"> </bean> <bean id="personalBankingDao" parent="daoTemplate" class="sample.spring.chapter03.bankapp.dao.PersonalBankingDaoImpl"></bean>
在上面的 xml 中,daoTemplate bean 定義了 fixedDepositDao 和 personalBankingDao bean 定義共享的公共配置。因爲 fixedDepositDao 和 personalBankingDao bean 定義都須要 databaseOperations 依賴項,daoTemplate bean 定義使用
若是
注意: 抽象 bean 不能做爲其餘 bean 定義的依賴項,也就是說,不能使用 <property> 或 <constructor-arg> 元素來引用抽象 bean 。
你可能已經注意到 daoTemplate bean 定義沒有指定 class特性。若是父 bean 定義沒有指定 class特性,則須要在子 bean 定義 (如 fixedDepositDao 和 personalBankingDao) 中指定 class 特性。注意,若是不指定 class 特性,則必須將 bean 定義爲抽象的,以使 Spring 容器不會去嘗試建立與之對應的 bean實例。spa
要驗證 fixedDepositDao 和 personalBankingDao bean 定義是否繼承了 daoTemplate bean 定義的 databaseOperations 屬性。請執行下面的 java 代碼。BankApp 類的 main 方法調用在 fixedDepositDao 和 personalBankingDao bean 中的方法,而這些 bean 調用 DatabaseOperations 實例上的方法。你會注意到,BankApp 的 main 方法成功運行。沒有拋出任何異常。若是沒有將 DatabaseOperations 實例注入 fixedDepositDao 和 personalBankingDao bean 中,那麼代碼將拋出 java.lang.NullPointerException。3d
package sample.spring.chapter03.bankapp; import org.apache.log4j.Logger; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import sample.spring.chapter03.bankapp.controller.FixedDepositController; import sample.spring.chapter03.bankapp.controller.PersonalBankingController; import sample.spring.chapter03.bankapp.domain.FixedDepositDetails; public class BankApp { private static Logger logger = Logger.getLogger(BankApp.class); public static void main(String args[]) { ApplicationContext context = new ClassPathXmlApplicationContext( "classpath:META-INF/spring/applicationContext.xml"); FixedDepositController fixedDepositController = context .getBean(FixedDepositController.class); fixedDepositController.submit(context .getBean(FixedDepositDetails.class).setDepositAmount(100) .setEmail("someemail@somedomain.com").setId(1).setTenure(10)); logger.info("Your fixed deposit details : " + fixedDepositController.get()); PersonalBankingController personalBankingController = context .getBean(PersonalBankingController.class); logger.info(personalBankingController.getMiniStatement()); } }
下圖 顯示了 fixedDepositDao 和 personalBankingDao bean 定義中,bean 定義繼承是如何工做的
上圖展現了 fixedDepositDao 和 personalBankingDao bean 定義從 daoTemplate bean 定義繼承了 databaseOperations 屬性(以 fixedDeopsitDa 和 personalBankingDao 標識的方框中的 property 屬性)。上圖還描述了 Spring 容器不會嘗試建立 與 daoTemplate bean 定義相對應的bean 實例,由於他被標記爲 abstract。
子 bean 定義從 父 bean 定義繼承一下配置信息: