Spring bean之间的关系

简介: 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 属性。



目录
相关文章
|
26天前
|
XML 安全 Java
|
3天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
3天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
9天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
42 6
|
10天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
61 3
|
1月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
24天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
32 1
|
2月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
83 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
2月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
138 1