1.13 继承Bean配置
1.13.1 问题
在Spring IoC容器中配置Bean时,你可能拥有超过一个共享某些公用配置的Bean,比如属性和元素中的属性。你常常必须为多个Bean重复这些配置。
1.13.2 解决方案
Spring允许你提取公用的Bean配置组成一个父Bean。从父Bean继承而来的Bean称作子Bean。子Bean从父Bean继承Bean配置,包括Bean属性和元素中的属性,避免重复配置。子Bean在必要时也可以覆盖继承的配置。
父Bean可以作为配置模板,也可以同时作为Bean的一个实例。但是,如果你希望父Bean只作为模板而不能检索,必须将abstract设置为true,要求Spring不要实例化这个Bean。
必须注意,并不是所有在父元素中定义的属性都将被继承。例如,autowire 和dependency-check属性不会从父Bean中继承。如果需要了解哪些属性从父Bean继承,而哪些不能,请参见关于Bean继承的Spring文档。
1.13.3 工作原理
假定你必须添加一个新的序列生成器实例,初始值和后缀与现有的生成器相同。
<beans ...>
<bean id="sequenceGenerator"
class="com.apress.springrecipes.sequence.SequenceGenerator">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
<property name="prefixGenerator" ref="datePrefixGenerator" />
</bean>
<bean id="sequenceGenerator1"
class="com.apress.springrecipes.sequence.SequenceGenerator">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
<property name="prefixGenerator" ref="datePrefixGenerator" />
</bean>
<bean id="datePrefixGenerator"
class="com.apress.springrecipes.sequence.DatePrefixGenerator">
<property name="pattern" value="yyyyMMdd" />
</bean>
</beans>
为了避免重复相同的属性,你可以用这些属性集声明一个基序列生成器。然后,两个序列生成器可以从这个基生成器中继承,这样它们也就自动拥有了那些属性集。如果子Bean和父Bean的class属性相同,就不需要指定。
<beans ...>
<bean id="baseSequenceGenerator"
class="com.apress.springrecipes.sequence.SequenceGenerator">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
<property name="prefixGenerator" ref="datePrefixGenerator" />
</bean>
<bean id="sequenceGenerator" parent="baseSequenceGenerator" />
<bean id="sequenceGenerator1" parent="baseSequenceGenerator" />
...
</beans>
继承的属性可以由子Bean覆盖。例如,你可以添加不同初始值的子序列生成器。
<beans ...>
<bean id="baseSequenceGenerator"
class="com.apress.springrecipes.sequence.SequenceGenerator">
<property name="initial" value="100000" />
<property name="suffix" value="A" />
<property name="prefixGenerator" ref="datePrefixGenerator" />
</bean>
<bean id="sequenceGenerator2" parent="baseSequenceGenerator">
<property name="initial" value="200000" />
</bean>
...
</beans>
现在,基序列生成器Bean可以恢复为Bean实例使用。如果你希望它仅作为模板,就必须将abstract属性设置为true。以后Spring将不会实例化这个Bean。
<bean id="baseSequenceGenerator" abstract="true"
class="com.apress.springrecipes.sequence.SequenceGenerator">
...
</bean>
你也可以忽略父Bean的类,让子Bean指定自己的类,特别是在父Bean与子Bean不在同一类层次结构但是共享同名属性的时候。在这种情况下,父Bean的abstract属性必须设置为true,因为父Bean不能实例化。例如,我们添加另一个也有initial属性的Reverse Generator类。
package com.apress.springrecipes.sequence;
public class ReverseGenerator {
private int initial;
public void setInitial(int initial) {
this.initial = initial;
}
}
现在,SequenceGenerator和ReverseGenerator不会扩展相同的基类,也就是说,它们不在相同的类层次结构中,但是具有同名的属性:initial。为了提取公共的initial属性,你需要一个没有定义class属性的父Bean——baseGenerator。
<beans ...>
<bean id="baseGenerator" abstract="true">
<property name="initial" value="100000" />
</bean>
<bean id="baseSequenceGenerator" abstract="true" parent="baseGenerator"
class="com.apress.springrecipes.sequence.SequenceGenerator">
<property name="suffix" value="A" />
<property name="prefixGenerator" ref="datePrefixGenerator" />
</bean>
<bean id="reverseGenerator" parent="baseGenerator"
class="com.apress.springrecipes.sequence.ReverseGenerator" />
<bean id="sequenceGenerator" parent="baseSequenceGenerator" />
<bean id="sequenceGenerator1" parent="baseSequenceGenerator" />
<bean id="sequenceGenerator2" parent="baseSequenceGenerator"/>
...
</beans>
图1-1显示了这个生成器Bean层次结构的对象图。
图1-1 生成器Bean层次结构的对象图