Bean 定义可以包含许多配置信息,包括构造函数参数、属性值和特定于容器的信息,如初始化方法、静态工厂方法名称等。子 bean 定义从父定义 继承配置数据。子定义可以重写一些值或根据需要添加其他值。使用父 bean 和子 bean 定义可以节省大量的输入。实际上,这是一种模板形式。

    如果您以编程方式使用 ApplicationContext 接口,则 ChildBeanDefinition(v2.5+ 建议使用 GenericBeanDefinition) 类表示子 bean 定义。大多数用户不在这个级别上与他们一起工作。相反,它们在类(如 ClassPathXmlApplicationContext)中以声明方式配置 bean 定义。当使用基于 xml 的配置元数据时,可以通过使用 parent 属性指定父 bean 作为该属性的值来指定子 bean 定义。下面的例子说明如何这样做:

    1. <bean id="inheritedTestBean" abstract="true"
    2. class="org.springframework.beans.TestBean">
    3. <property name="name" value="parent"/>
    4. <property name="age" value="1"/>
    5. </bean>
    6. <bean id="inheritsWithDifferentClass"
    7. class="org.springframework.beans.DerivedTestBean"
    8. parent="inheritedTestBean" init-method="initialize">
    9. <property name="name" value="override"/>
    10. <!-- 年龄属性值 1 将从父级继承 -->
    11. </bean>

    如果没有指定子 bean 定义,则子 bean 定义使用父定义中的 bean 类,但也可以重写它。在后一种情况下,子 bean 类必须与父类兼容(即它必须接受父类的属性值)。

    子 bean 定义继承父 bean 的作用域、构造函数参数值、属性值和方法重写,并具有添加新值的选项。指定的任何作用域、初始化方法、销毁方法或静态 factory 方法设置都会覆盖相应的父级设置。

    其余的设置始终取自子定义:依赖项、自动装配模式、依赖项检查、单例和延迟初始化。

    前面的示例使用 abstract 属性将父 bean 定义显式标记为 abstract。如果父定义没有指定类,则需要显式地将父 bean 定义标记为 abstract,如下面的示例所示:

    1. <bean id="inheritedTestBeanWithoutClass" abstract="true">
    2. <property name="name" value="parent"/>
    3. <property name="age" value="1"/>
    4. </bean>
    5. <bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
    6. parent="inheritedTestBeanWithoutClass" init-method="initialize">
    7. <property name="name" value="override"/>
    8. <!-- age=1 将从父 bean 定义中继承-->
    9. </bean>

    默认情况下,ApplicationContext 预实例化所有单例。因此,重要的是(至少对于单例 bean 来说),如果您有一个(父)bean 定义,您只打算将其用作模板,并且该定义指定了一个类,那么必须确保将 abstract 属性设置为 true,否则应用程序上下文将实际(尝试)预实例化抽象 bean。

    :::tips 总结如下,被标识为 abstract 的 bean:

    1. 它不会被实例化,也就是不会在 ioc 容器中存在实例
    2. 它可以是一个正常的普通类,也就是在类声明上可以不是 abstract
    3. 所以可以看成是一个公共模板方式 :::