不但可以通过< ref >引用另一个Bean,建立起Bean和Bean之间的依赖关系,相似的,< bean >元素标签之间也可以建立类似的关系,完成一些特殊的功能。
1.继承
OOP思想告诉我们,如果多个类拥有相同的方法和属性,则我们可以引入一个父类,在父类中定义这些共同的方法和属性,以消除重复的代码。相似的,如果多个< bean >存在相同的配置信息,Spring允许我们定义一个父< bean >,子< bean >将自动继承父< bean >的配置信息。
我们通过一个实例,对使用和未使用父子< bean >的配置进行比较,从中看出父子< bean >给配置带来的便利性:
<bean id="car1" class="com.baobaotao.Car" p:brand="红旗CA72" p:price="2000.00" p:color="黑色"/>
<bean id="car2" class="com.baobaotao.Car" p:brand="红旗CA72" p:price="2000.00" p:color="红色"/>
上面的代码配置了两个Car Bean,我们发现这两个Bean的配置存在大量重复的信息,事实上,两者除了color属性配置值不一样之外,其他的配置信息都相同。通过父子< bean >的继承关系就可以很好地消除这种重复的信息。
<bean id="abstractCar" class="com.baobaotao.tagdepend.Car" p:brand="红旗CA72" p:price="2000.00" p:color="黑色" abstract="true"/>
<bean id="car3" p:color="红色" parent="abstractCar"/>
<bean id="car4" p:color="白色" parent="abstractCar"/>
上面的代码中,car3和car4这两个< bean >都继承于abstractCar的< bean >,Spring会将父< bean >的配置信息传递给子< bean >,如果子< bean >提供了父< bean >已有的配置信息,子< bean >的配置信息将覆盖父< bean >的配置信息。
父< bean >的主要功能是为了简化子< bean >的配置,所以一般声明为abstract=“true”,表示这个< bean >不实例化为一个对应的Bean。如果没有这条声明语句,则Spring IoC容器会实例化为一个名为abstractCar的Bean。
2.依赖
一般情况下,可以使用< ref >元素标签建立对其他Bean的依赖关系,Spring负责管理这些Bean的关系,当实例化一个Bean时,Spring保证该Bean所依赖的其他Bean已经初始化。
但在某些情况之下,这种Bean之间的依赖关系并不是那么明显。我们来举一个例子:
”宝宝淘“论坛拥有许多系统参数(如会话过期时间、缓存更新时间等),这些系统参数用于控制系统的运行逻辑。我们用一个SystemSettings类表示这些系统参数:
public class SystemSettings{
public static int SESSION_TIMEOUT=30;
public static int REFRESH_CYCLE=60;
}
在SystemSettings中为每一个系统参数提供了默认值,但一个灵活的论坛必须提供一个管理后台,在管理后台中可以调整这些系统参数并保存到后台数据之中,在系统启动时,初始化城西从数据库后台加载这些系统参数的配置值以覆盖默认的值:
public class SysInit{
public SysInit(){
SystemSettings.SESSION_TIMEOUT=10;
SystemSettings.REFRESH_CYCLE=100;
}
}
假设我们的论坛有一个缓存刷新管理器,它需要根据系统参数SystemSetters.REFRESH_CYCLE创建缓存刷新定时任务:
public class CacheManager{
public CacheManager(){
Timer timer=new Timer();
TimerTask cacheTask=new TimerTask();
timer.schedule(cacheTask,0,SystemSettings.REFRESH_CYCLE);
}
}
在上面的实例中,CacheManager依赖于SystemSetter,而SystemSetter的值由SysInit负责初始化。虽然CacheManager不直接依赖于SysInit,但从逻辑上看,CacheManager希望在SysInit加载并完成系统参数设置之后再启动,以避免调用不到真实的系统参数值。如果这三个Bean都在Spring配置文件中定义,我们需要保证SysInit在CacheManager之前进行初始化。
Spring允许用户通过depend-on属性指定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好:
<bean id="manager" class="com.baobaotao.tagdepend.CacheManager" depend-on="sysInit"/>
<bean id="sysInit" class="com.baobaotao.tagdepend.SysInit"/>
我们将sysInit指定为manager前置依赖的Bean,这样就可以保证manager Bean在实例化并运行时所引用的系统参数是最新的设置值而不是原来的默认值。
如果前置依赖于多个Bean,则可以使用逗号,空格或分号的方式创建Bean的名称。
3.引用
假设一个< bean>要引用另一个< bean >的id属性值,我们当然可以直接使用以下的配置方式:
Spring提供了一个< idref >元素标签,通过< idref >引用另一个< bean >的名字。
<bean id="car" class="com.baobaotao.tagdepend.Car"/>
<bean id="boss" class="com.baobaotao.tagdepend.Boss">
<property name="carld">
<idref bean="car"/>
</property>
</bean>
4.整合多个配置文件
对于一个大型的应用来说,可能有多个XML配置文件,在启动Spring容器时,可以通过一个String数组指定这些配置文件。Spring还允许我们通过< import resource >将多个配置文件引入到一个文件之中,进行配置文件的集成。这样在启动Spring容器时,仅需指定这个合并好的配置文件即可:
以下是beans2.xml的配置文件,它引入了beans1.xml配置文件。
<import resource="classpath:com/baobaotao/impt/beans1.xml"/>
<bean id="boss1" class="com.baobaotao.fb.Boss"p:name="John" p:car-ref="car1"/>
<bean id="boss2" class="com.baobaotao.fb.Boss"p:name="John" p:car-ref="car2"/>
需要指出的是:如果一个配置文件a.xml的< bean >引用到另一个配置文件b.xml的< bean >,并不一定需要通过< import >引入b.xml,只需在启动Spring容器时,a.xml和b.xml都在配置文件列表中就可以了,Spring容器会自动在内存中合并它们。
对于大型应用来说,为了防止开发时配置文件的资源竞争,或为了使模块便于拆卸,往往每个模块都拥有自己独立的配置文件。应用层面提供一个整合的配置文件,通过< import >将各个模块整合起来。这样容器启动时,只需关注这个整合的配置文件就可以了。