4.7 Bean 定义的继承

bean 的定义可以包含很多配置信息包括构造方法参数,属性值和容器指定的信息,比 如初始化方法,静态工厂方法名称等。子 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">
<property name="name" value="override"/>
<!-- age属性值1将会从父bean中继承过来 -->
</bean>

如果没有指定一个子 bean 使用父 bean 的类,但也可以覆盖它。在这种情形中,子 bean的类必须和父 bean 兼容,也就是说,它必须接受父 bean 的属性值。

子 bean 的定义继承构造方法参数值,属性值,还有父 bean 的方法覆盖,添加新值的 选择。任何你指定的初始化方法,销毁方法,和/或 static 工厂方法设置会覆盖对应父 bean 中的设置。

剩下的设置通常是从子 bean 来定义:依赖,自动装配模式,依赖检测,单例,范围, 延迟初始化。

前面的示例明确地使用了 abstract 属性来标识了父 bean 的定义。如果父 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属性值1将会从父bean中继承过来 -->
</bean>

父 bean 不会被实例化,因为它自己是不完整的,而且也明确地被 abstract 标记。当 bean 的定义是 abstract 这样的,那么它也仅仅被用做纯 bean 定义的模板,作为子 bean 定义的父 bean。尝试使用这种自身是 abstract 的父 bean,作为另外一个 bean 参考的属 性来指代它,或者使用父 bean 的 id 来明确使用 getBean()方法调用,会返回错误。相似 地,容器内部的 preInstantiateSingletons()方法忽略了抽象 bean 的定义。

注意

默认情况下,预实例化所有单例 bean。因此,如果你有仅仅想用作模板的(父)bean, 而且这个 bean 指定了一个类,那么必须将 abstract 属性设置为 true,这点是很重要的。否 则,应用上下文就会(尝试)预实例化 abstract 的 bean。