3.7 Spring 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"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
子bean定义使用父定义中的bean类(如果没有指定),但也可以覆盖它。 在后一种情况下,子bean类必须与父兼容,也就是说,它必须接受父的属性值。
子bean定义从父级继承 作用域,构造函数参数值,属性值和方法覆盖,并具有添加新值的选项。 您指定的任何作用域,初始化方法,销毁方法和/或static
工厂方法设置将覆盖相应的父设置。
剩下的设置是 always 取自子定义:depends on, autowire模式,依赖性检查, singleton , lazy init 。
前面的示例通过使用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不能自己实例化,因为它是不完整的,它也被显式标记为“抽象”。 当定义是这样的“抽象”时,它只能用作纯模板bean定义,用来作为子定义的父定义。 试图使用这样的抽象父bean,通过引用它作为另一个bean的ref属性或使用父bean id执行显式的getBean()
调用,返回一个错误。 同样,容器的内部preInstantiateSingletons()
方法忽略定义为抽象的bean定义。
ApplicationContext 默认实例化所有单例。 因此,重要的是(至少对于单例bean)如果你有一个(父)bean定义,你打算只使用作为一个模板,并且这个定义指定一个类,你必须确保设置 abstract 属性 为 true ,否则应用程序上下文将实际(尝试)预实例化abstract bean。 |