Bean 定義繼承

一個 Bean 定義可以包含大量配置資訊,包括建構函式引數、屬性值以及容器特定的資訊,例如初始化方法、靜態工廠方法名等等。子 Bean 定義繼承父定義的配置資料。子定義可以覆蓋某些值或根據需要新增其他值。使用父子 Bean 定義可以節省大量工作。實際上,這是一種模板化形式。

如果你以程式設計方式使用 ApplicationContext 介面,子 Bean 定義由 ChildBeanDefinition 類表示。大多數使用者不會在此級別上使用它們。相反,他們會在像 ClassPathXmlApplicationContext 這樣的類中以宣告方式配置 Bean 定義。當你使用基於 XML 的配置元資料時,可以使用 parent 屬性來指示子 Bean 定義,並將父 Bean 指定為該屬性的值。以下示例展示瞭如何做到這一點

<bean id="inheritedTestBean" abstract="true"
		class="org.springframework.beans.TestBean">
	<property name="name" value="parent"/>
	<property name="age" value="1"/>
</bean>

<bean id="inheritsWithDifferentClass"
		class="org.springframework.beans.DerivedTestBean"
		parent="inheritedTestBean" init-method="initialize">  (1)
	<property name="name" value="override"/>
	<!-- the age property value of 1 will be inherited from parent -->
</bean>
1 注意 parent 屬性。

如果未指定類,子 Bean 定義將使用父定義中的 Bean 類,但也可以覆蓋它。在後一種情況下,子 Bean 類必須與父類相容(即,它必須接受父類的屬性值)。

子 Bean 定義從父定義繼承作用域、建構函式引數值、屬性值和方法覆蓋,並且可以選擇新增新值。你指定的任何作用域、初始化方法、銷燬方法或 static 工廠方法設定都會覆蓋相應的父設定。

其餘設定始終取自子定義:depends-on、自動裝配模式、依賴檢查、singleton 和延遲初始化。

前面的示例透過使用 abstract 屬性將父 Bean 定義顯式標記為抽象。如果父定義未指定類,則必須顯式將父 Bean 定義標記為 abstract,如下例所示

<bean id="inheritedTestBeanWithoutClass" abstract="true">
	<property name="name" value="parent"/>
	<property name="age" value="1"/>
</bean>

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
		parent="inheritedTestBeanWithoutClass" init-method="initialize">
	<property name="name" value="override"/>
	<!-- age will inherit the value of 1 from the parent bean definition-->
</bean>

父 Bean 本身無法例項化,因為它不完整,並且也被顯式標記為 abstract。當一個定義是 abstract 時,它只能作為純粹的模板 Bean 定義使用,作為子定義的父定義。嘗試單獨使用此類 abstract 父 Bean(透過將其作為另一個 Bean 的 ref 屬性引用或使用父 Bean ID 進行顯式的 getBean() 呼叫)將返回錯誤。同樣,容器的內部 preInstantiateSingletons() 方法會忽略定義為抽象的 Bean 定義。

ApplicationContext 預設會預先例項化所有 singleton Bean。因此,重要的一點(至少對於 singleton Bean 來說)是,如果你有一個(父)Bean 定義僅打算用作模板,並且此定義指定了類,則必須確保將 abstract 屬性設定為 true,否則應用上下文將實際(嘗試)預先例項化該 abstract Bean。