Bean 的 depends-on 属性

前言

今天下午在复习 Spring Bean 相关知识的时候突然一个新的东东进入了我的认知世界,他就是……

!!depends-on !!

NM这是啥!

不是有 ref 了吗!!

这干吗用的啊!!!

平静下来之后,我进行了网上冲浪。于是就有了下文……

一、depends-on 究竟是啥?

首先放上官方文档描述:

If a bean is a dependency of another that usually means that one bean is set as a property of another. Typically you accomplish this with the element in XML-based configuration metadata. However, sometimes dependencies between beans are less direct; for example, a static initializer in a class needs to be triggered, such as database driver registration. The depends-on attribute can explicitly force one or more beans to be initialized before the bean using this element is initialized.

如果一个bean是另一个bean的依赖项,通常意味着将一个bean设置为另一个bean的属性。 通常,您可以使用基于XML的配置元数据中的标签来完成此操作。 但是,有时bean之间的依赖性不太直接。 比方说,需要触发类中的静态初始化器,例如数据库驱动程序注册。 depends-on 属性可以显式地强制初始化一个或多个使用该元素的bean之前的bean。

depends-onref 属性都可以作为一个 bean 依赖另一个 bean 的属性

且依赖会使被依赖项先于依赖项进行初始化,而后于依赖项被销毁。举个栗子:

先写好 Person.java 以及 Phone.java(Getter and Setter 、toString 这里就不写啦)

// Person.java

public class Person {
    private String name;
    private int age;
    private Phone phone;

    public Person() {
        System.out.println("Person 被实例化了!");
    }

    public void init() {
        System.out.println("Person 被初始化了!");
    }

    public void destroy() {
        System.out.println("Person 被销毁了!");
    }
}
// Phone.java

public class Phone {
    private String brand;
    private String model;
    private int price;

    public Phone() {
        System.out.println("Phone 被实例化了!");
    }

    public void init() {
        System.out.println("Phone 被初始化了!");
    }

    public void destroy() {
        System.out.println("Phone 被销毁了!");
    }
}

定义好两个类之后开始配置 beans(在这里配置 depends-on 或者 ref 属性)

<!-- beans-relation.xml -->

<!-- Phone bean 定义 -->
<bean id="phone_0" class="indi.homn.relation.Phone"
      p:brand="HUAWEI" p:model="Mate30 Pro" p:price="6899"
      init-method="init" destroy-method="destroy"/>
<!-- Person bean 定义 -->
<bean id="person_0" class="indi.homn.relation.Person"
      p:name="xxx" p:age="10" depens-on="phone_0"	<!-- depends-on 属性在这里 -->
      init-method="init" destroy-method="destroy"/>

配置好 beans 之后写测试程序

// Main.java

//打开容器,并且实例化容器中的 beans
AbstractApplicationContext context = 
    new ClassPathXmlApplicationContext("beans-relation.xml");

//关闭容器,并且销毁容器中的 beans
context.registerShutdownHook();

运行看看输出了什么

// Output

Phone 被实例化了!
Phone 被初始化了!	 <-- 被依赖项 Phone 先初始化
Person 被实例化了!
Person 被初始化了!
Person 被销毁了!
Phone 被销毁了!		  <-- 被依赖项 Phone 后被销毁

(只有 scope 属性为 singleton 的 bean 才会被销毁,prototype 不可以。bean 配置 scope 默认为 singleton)

beans-relation.xml 文件中的 depends-on 换成 ref 得出的结果是一样的,这里不做演示。

那他们有什么区别?当然有!请接下来看。

二、与 ref 属性的区别

1. 代码执行顺序

一开始还以为是将 Phone bean 定义在 Person bean 之前的关系,于是我调换了他们的顺序

<!-- beans-relation.xml -->

<!-- Person bean 定义 -->
<bean id="person_0" class="indi.homn.relation.Person"
      p:name="xxx" p:age="10" depens-on="phone_0"
      init-method="init" destroy-method="destroy"/>

<!-- Phone bean 定义 -->
<bean id="phone_0" class="indi.homn.relation.Phone"
      p:brand="HUAWEI" p:model="Mate30 Pro" p:price="6899"
      init-method="init" destroy-method="destroy"/>

结果还是和上面说的一样,于是我将 depands-on 换成了 ref 属性又试了一下。

MASAKA!!!! 也会一样吗!!!

// Output

Person 被实例化了!	 <-- 依赖项 Person 先被实例化
Phone 被实例化了!
Phone 被初始化了!	 <--
Person 被初始化了!
Person 被销毁了!
Phone 被销毁了!		  <-- 被依赖项 Phone 后被销毁

打扰了

依赖项 Person 先被实例化了!奇怪的知识增加了!!!

这里应该有小伙伴们都要问了:不是说好被依赖项先的吗!?

确实,不过这里的 “先” 指的不是实例化,而是初始化。我们看上面输出的第二个箭头(<--):

被依赖项 Phone 确实是先于依赖项 Person 被初始化的,且 Phone 也是后于 Person 被销毁的。

而这次 Person 因为定义在 Phone 之前,IoC容器会依个进行实例化,而如果用上 depends-on 属性,就会强制先实例化被依赖的 Phone

2. 是否会将对象注入到自己属性中

直截了当说:

  • ref 会,而且要求依赖项有被依赖项这个类的属性(即 Person 类的属性中要有 Phone);
  • depends-on 不会,甚至依赖项可以不拥有被依赖项这个类的属性。

保持其他文件不变,仅在 Main.java 文件下方加两行代码:

// Main.java

//打开容器,并且实例化容器中的 beans
AbstractApplicationContext context = 
    new ClassPathXmlApplicationContext("beans-relation.xml");

//关闭容器,并且销毁容器中的 beans
context.registerShutdownHook();

//从 IoC 容器中取用 id 为 person_0 的 bean   
Person person = (Person) context.getBean("person_0");

//输出 person 的信息
System.out.println(person);

- 依赖属性为 ref

// Output
// 省略实例化、初始化和销毁的顺序

Person{name='xxx', age=10, phone=Phone{brand='HUAWEI', model='Mate30 Pro', price=6899}}

Person 被注入了 😛

- 依赖属性为 depens-on

// Output
// 省略实例化、初始化和销毁的顺序

Person{name='xxx', age=10, phone=null}

Person 没有被注入 =^=

本例中 PersonPhone 的依赖关系还是比较强的(Person 中含有 Phone 的属性)

不过,与其说 depends-on 属性不能注入属性,倒不如说其不需要注入。比如说有时候依赖项与被依赖项之间的关系没有那么强,仅需要被依赖项先被实例化,那用 depends-on 可以说非常合适了。

三、depends-on 怎么用?

上面给的官方文档的描述已经说过在哪些情况下会使用 depends-on 这个属性

有时bean之间的依赖性不太直接。 比方说,需要触发类中的静态初始化器,例如数据库驱动程序注册。

这里引用他人的一篇写的很好的博客来给大家解释,我怕给他写毁了,就直接搬运过来

spring depends-on

结束语

啊!第一次写技术博客,希望大佬们发现错误了都能给我指出来。谢谢!!!

参考:

1. Spring - bean的依赖关系(depends-on属性)

2. Spring bean的初始化及销毁

3. spring depends-on

posted @ 2020-03-03 10:43  HOMMEEN  阅读(726)  评论(0编辑  收藏  举报