概述继承依赖关系引用
概述
在学习 bean 的加载过程时不了解 bean 循环依赖的概念,因此在查阅相关资料时发现 bean 之间除了依赖关系还有其他一些关系。因此本章就对 bean 之间的关系进行整理,bean 之间的关系可以通过对 bean元素标签的设置起作用,完成一些特殊的功能。
在 Spring 容器中,两个 Bean 之间除了注入关系外,还存在继承、依赖和引用关系。
- 继承关系:在 Spring 容器当中允许使用 abstract 标签来定义一个父 bean,parent 标签来定义一个子 bean。子 bean 将自动继承父 bean 的配置信息。
- 依赖关系:Spring 允许用户通过 depends-on 标签来设定 bean 的前置依赖 bean,前置依赖的 bean 会在本 bean 实例化之前创建好,供本 bean 使用。
- 引用关系:不光可以通过 ref 标签来引用其他的 bean,而且可以通过 idref 标签来引用其他 bean 的名字。它的主要作用是:在 Spring 容器启动的时候就可以检查引用关系的正确性,从而可以提前发现配置信息是否存在错误。
继承
如果多个 bean 存在相同的配置信息,Spring 允许定义一个父 Bean,子 bean 将自动继承父 bean 的配置信息。Spring 会将父 bean 的配置信息传递个子 bean,如果子 bean 提供了父 bean 已有的配置信息,那么子 bean 的配置信息将覆盖父 bean 的配置信息。
新建一个 Car 类
public class Car {
private int maxSpeed ;
private double price ;
private String brand ;
private String color;
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Car{" +
"maxSpeed=" + maxSpeed +
", price=" + price +
", brand='" + brand + '\'' +
", color='" + color + '\'' +
'}';
}
}
然后在 beans.xml 文件中配置:
<?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="car1" class="com.msdn.bean.Car" p:maxSpeed="240" p:price="5600" p:brand="宝马" p:color="红色" />
<bean id="car2" class="com.msdn.bean.Car" p:color="银色" parent="car1"/>
</beans>
上述代码中 car1 虽然被声明为父 bean,但是没有声明为 abstract=”true”,意味着父 bean 也会被实例化。如果仅仅是声明为抽象父类,不需要实例化,则可以定义 abstract=”true” 。
测试代码
@Test
public void inheritTest(){
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Car car1 = (Car) beanFactory.getBean("car1");
System.out.println(car1);
Car car2 = (Car) beanFactory.getBean("car2");
System.out.println(car2);
}
运行结果为:
Car{maxSpeed=240, price=5600.0, brand='宝马', color='红色'}
Car{maxSpeed=240, price=5600.0, brand='宝马', color='银色'}
从结果可以看出,car2 继承了 car1 的所有属性,只是改变了 color 属性,其他属性都跟 car1 相同。
依赖关系
在 Spring 容器中,当使用 depends-on 标签建立对其他 Bean 的依赖关系时,Spring 容器负责管理这些 Bean 的关系,当实例化一个 Bean 时,容器保证该 Bean 所依赖的 Bean 已经初始化;如果前置依赖多个 Bean,可以通过逗号或空格方式配置 Bean 名称。
depends-on 属性只是表明依赖关系(不一定会引用),这个依赖关系决定了被依赖的 bean 必定会在依赖 bean 之前被实例化,反过来,容器关闭时,依赖 bean 会在被依赖的 bean 之前被销毁。
新建一个 Person 类
public class Person {
private String name;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 拥有一辆car=" + car +
'}';
}
}
在 beans.xml 中配置
<?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="car1" class="com.msdn.bean.Car" p:maxSpeed="240" p:price="5600" p:brand="宝马" p:color="红色" />
<!--<bean id="car2" class="com.msdn.bean.Car" p:color="银色" parent="car1"/>-->
<bean id="person" class="com.msdn.bean.Person" p:name="herish" depends-on="car1" />
</beans>
测试代码如下:
@Test
public void relyTest(){
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Car car1 = (Car) beanFactory.getBean("car1");
System.out.println(car1);
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
}
执行结果为:
Car{maxSpeed=240, price=5600.0, brand='宝马', color='红色'}
Person{name='herish', 拥有一辆car=null}
从结果可以看出,car1 会先于 person 被实例化,而 person 不会将 car1 注入到自己的属性中。
引用
修改 Person 类
public class Person {
private String name;
private Car car;
private String desc;
//get set方法
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 拥有一辆car=" + car +
'}';
}
}
新建 StringBean 类
public class StringBean {
public StringBean() {
System.out.println("当作String类");
}
}
修改 beans.xml 文件
<?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="abstractCar" class="com.msdn.bean.AbstractCar" p:maxSpeed="240" p:price="56000" abstract="true"/>-->
<bean id="car1" class="com.msdn.bean.Car" p:maxSpeed="240" p:price="5600" p:brand="宝马" p:color="红色" />
<!--<bean id="car2" class="com.msdn.bean.Car" p:color="银色" parent="car1"/>-->
<bean id="stringBean" class="com.msdn.bean.StringBean" />
<bean id="person" class="com.msdn.bean.Person" p:name="herish" depends-on="car1" />
<bean id="person2" class="com.msdn.bean.Person" p:car-ref="car1">
<property name="name" value="hresh" />
<!--<property name="car">
<idref bean="car1" />
</property>-->
<property name="desc">
<idref bean="stringBean" />
</property>
</bean>
</beans>
测试代码如下
@Test
public void refTest(){
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Person person = (Person) beanFactory.getBean("person2");
System.out.println(person.getDesc());
System.out.println(person);
}
执行结果为:
stringBean
Person{name='hresh', 拥有一辆car=Car{maxSpeed=240, price=5600.0, brand='宝马', color='红色'}}
在测试过程中发现,标签引用 Car 的时候,运行结果会报错,错误信息如下:
nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.msdn.bean.Car' for property 'car': no matching editors or conversion strategy found
StringBean 类并未被初始化, 的 bean 属性相当于 value 属性。