1.bean之间的继承关系
承接上一篇文章,在src目录下新建一个beans-relation.xml配置文件,导入p命名空间。使用com.spring.beans.autowire包中的类,在不考虑继承和依赖的情况配置如下代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.spring.beans.autowire.Address" p:city="Beijing" p:street="WUDAOK"></bean>
<bean id="address2" class="com.spring.beans.autowire.Address" p:city="Beijing" p:street="WANGFUJING"></bean>
</beans>
主方法中如下:
package com.spring.beans.autowire;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-relation.xml");
Address address=(Address)ctx.getBean("address");
System.out.println(address);
Address address2=(Address)ctx.getBean("address2");
System.out.println(address2);
}
}
输出结果为:
观察上述两个bean的配置,发现class和city的值都是一样的,能否采用配置之间的继承关系来避免相同的部分反复写?可以将上述bean的配置改为下面这样:
则输出结果为:
上述就是一种配置上的继承关系,使用bean的parent属性。
1.Spring允许继承bean的配置,被继承的bean称为父bean,继承这个父bean的bean称为子bean。
2.子bean从父bean中继承配置,包括bean的属性配置。
3.子bean也可以覆盖从父bean继承过来的配置。
4.父bean可以作为配置模板,也可以作为bean实例。若只想把父bean作为模板,可以设置<bean>的abstract属性为true,这样Spring不再实例化这个bean。
5.并不是<bean>元素里所有的属性都会被继承,比如:autowire,abstract等。
6.可以忽略父bean的class属性,让子bean指定自己的类,而共享相同的属性配置,但此时父bean的abstract必须设为true。如下:
2.bean之间的依赖关系
Spring允许用户通过depends-on属性设定bean前置依赖的bean,前置依赖的bean会在本bean实例化之前创建好,否则报错。未配置依赖时如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" p:city="Beijing" p:street="WUDAOK" abstract="true"></bean>
<bean id="address2" class="com.spring.beans.autowire.Address" p:street="gongzhufen" parent="address"></bean>
<bean id="person" class="com.spring.beans.autowire.Person" p:name="Tom" p:address-ref="address2"></bean>
</beans>
输出结果为:
由于为配置car,所以其输出为null,现在要求配置Person时必须有个关联的car,即person这个bean依赖于一个Car的实例。配置依赖后:
depends-on的意思是实例化person的时候必须先实例化好一个car,当然与代码写的先后顺序无关。如果IOC容器没有类型为Car的bean,则报错。输出结果为:
此时可以想象得到,很多读者会问,配置依赖之后car的输出还是null,那这种依赖关系配置的有什么用呢?事实上,depends-on用来指定Bean初始化及销毁时的顺序的。如上面person中定义depend-on=“car”,这意味着Spring总会保证car在person之前实例化,总是在person之后再销毁。它仅仅只是指定了一个顺序,而不是说要给person的car的属性去赋值。它适用的场景:比如我们需要对某个事物进行监听,它们之间并没有直接地依赖关系,但它们的启动顺序必须是监听器在这个事物之前。
一个bean可能会依赖于多个bean,这个时候可以用逗号、空格、分号来配置多个。如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" p:city="Beijing" p:street="WUDAOK" abstract="true"></bean>
<bean id="address2" class="com.spring.beans.autowire.Address" p:street="gongzhufen" parent="address"></bean>
<bean id="car" class="com.spring.beans.autowire.Car" p:brand="audi" p:price="20000"></bean>
<bean id="person" class="com.spring.beans.autowire.Person" p:name="Tom" p:address-ref="address2" depends-on="car address2"></bean>
<!-- <bean id="person" class="com.spring.beans.autowire.Person" p:name="Tom" p:address-ref="address2" depends-on="car,address2"></bean>
<bean id="person" class="com.spring.beans.autowire.Person" p:name="Tom" p:address-ref="address2" depends-on="car;address2"></bean> -->
<!--上述 配置多个依赖时使用逗号、空格、分号都可以-->
</beans>
注意:Spring不支持循环依赖,即A依赖于B,B又依赖于A,这是错误的。
还值得注意的是,spring管理的bean默认都是单例模式,单例模式并不是说IOC容器里面只能创建某个类型的一个实例。比如前几篇文章中也可以同时创建多个Car的实例。Spring的单例模式意思是在调用getBean( )方法时,如果id值是一样的,则不再重新创建一个bean,而是每次都调用同一个bean的实例。如下所示,依然保持上述的配置文件不变,在主方法中二次获取person这个bean。
package com.spring.beans.autowire;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-relation.xml");
/*Address address=(Address)ctx.getBean("address");
System.out.println(address);*/
/*Address address2=(Address)ctx.getBean("address2");
System.out.println(address2);*/
Person person=(Person)ctx.getBean("person");
System.out.println(person);
Person person1=(Person)ctx.getBean("person");
System.out.println(person);
System.out.println(person==person1);//判断获取的两个对象是否是同一个
}
}
输出结果:
结果为true,则证明两次获取是同一个对象。如果每次调用getBean( )方法都想获取一个新的对象怎么办?把scope的属性值设为prototype即可,默认为singleton时scope可以省略不写。如下:
这时输出结果为:
此时获取到的不再是同一个对象,输出了false。