Spring bean之间的关系

hresh 588 0

Spring bean之间的关系

概述

在学习 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 类并未被初始化,<idref>的 bean 属性相当于 value 属性。

发表评论 取消回复
表情 图片 链接 代码

分享