Spring 教程

Spring 使用 depends-on 属性

如果一个 Bean 是另一个 Bean 的依赖,这通常意味着一个 Bean 被设置为另一个 Bean 的属性。通常情况下,您可以通过基于 XML 的配置元数据中的 <ref/> 元素来实现这一点。例如:

<bean id="exampleBean" class="examples.ExampleBean">
   <!-- 使用嵌套 ref 元素注入依赖的 bean -->
   <property name="beanOne">
       <ref bean="anotherExampleBean"/>
   </property>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>

不过,有时 Bean 之间的依赖关系并不那么直接(即依赖的 bean 不是定义 bean 的属性)。例如,需要触发一个类中的静态初始化块,如数据库驱动程序注册,例如:

public class JdbcAccountDao {

   static {
       try {
           // 注册数据库驱动
           Class.forName("com.mysql.jdbc.Driver");
       } catch (Exception e) {
           e.printStackTrace();
       }
   }

   public JdbcAccountDao() {
       System.out.println("JdbcAccountDao()");
   }

}

depends-on 属性

在 Spring 中,bean 元素提供了一个 depends-on 配置属性,用于指定 bean 之间的依赖关系。通过使用 depends-on 属性,你可以确保在容器启动时,指定的 bean 会在其他 bean 之前被实例化和初始化。

下面的示例使用 depends-on 属性表达了对单个 Bean 的依赖关系:

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />

在上面示例中,beanOne 将在 manager 实例化后才会被实例化,注意:ExampleBean 和 ManagerBean 类在代码上没有任何依赖关系,谁也不是谁的依赖。

如果要表达对多个 Bean 的依赖关系,请提供一个 Bean 名称列表作为 depends-on 属性的值(逗号、空格和分号都是有效的分隔符),例如:

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
   <property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

在上面的示例中,beanOne 的实例化和初始化将在 manager 和 accountDao 之后发生,因为 depends-on 属性指定了这两个 bean。

另外,如果存在循环依赖关系(A 依赖于 B,B 依赖于 A),则使用 depends-on 属性无法解决循环依赖问题,可能会导致应用程序启动失败。在这种情况下,你可能需要考虑重新设计你的 bean 结构,或者使用其他解决循环依赖的方法,如构造函数注入、@Lazy 注解等。

提示:depends-on 属性既可以指定初始化时依赖项,也可以指定对应的销毁时依赖项 (仅在单例 bean 的情况下)。在给定 bean 本身被销毁之前,首先销毁与给定 bean 定义依赖关系的 bean。因此,依赖还可以控制关机顺序。例如:

applicationContext-ioc-demo3.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"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="beanOne" class="com.hxstrive.spring5.ioc.demo3.ExampleBean" depends-on="manager,accountDao"
         init-method="init" destroy-method="destroy">
       <property name="manager" ref="manager" />
   </bean>

   <bean id="manager" class="com.hxstrive.spring5.ioc.demo3.ManagerBean" init-method="init" destroy-method="destroy" />
   <bean id="accountDao" class="com.hxstrive.spring5.ioc.demo3.JdbcAccountDao" init-method="init" destroy-method="destroy" />

</beans>

JdbcAccountDao.java:

package com.hxstrive.spring5.ioc.demo3;

public class JdbcAccountDao {

   public void init() {
       System.out.println("JdbcAccountDao.init()");
   }

   public void destroy() {
       System.out.println("JdbcAccountDao.destroy()");
   }

   public JdbcAccountDao() {
       System.out.println("JdbcAccountDao()");
   }

}

ManagerBean.java:

package com.hxstrive.spring5.ioc.demo3;

public class ManagerBean {

   public void init() {
       System.out.println("ManagerBean.init()");
   }

   public void destroy() {
       System.out.println("ManagerBean.destroy()");
   }

   public ManagerBean() {
       System.out.println("ManagerBean()");
   }

}

ExampleBean.java:

package com.hxstrive.spring5.ioc.demo3;

public class ExampleBean {
   private ManagerBean manager;

   public void init() {
       System.out.println("ExampleBean.init()");
   }

   public void destroy() {
       System.out.println("ExampleBean.destroy()");
   }

   public ExampleBean() {
       System.out.println("ExampleBean()");
   }

   public ManagerBean getManager() {
       return manager;
   }

   public void setManager(ManagerBean manager) {
       this.manager = manager;
   }
}

Main.java:

package com.hxstrive.spring5.ioc.demo3;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

   public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-ioc-demo3.xml");
       context.getBean(ExampleBean.class);

       // 注册关闭钩子,触发 bean 的销毁方法
       if(context instanceof AbstractApplicationContext) {
           ((AbstractApplicationContext)context).registerShutdownHook();
       }
   }

}

运行示例,输出如下:

ManagerBean()
ManagerBean.init()
JdbcAccountDao()
JdbcAccountDao.init()
ExampleBean()
ExampleBean.init()
ExampleBean.destroy()
JdbcAccountDao.destroy()
ManagerBean.destroy()

从上面的输出结果可知,初始化是先初始化依赖的 bean,销毁和初始化顺序相反。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号