如果一个 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()"); } }
在 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,销毁和初始化顺序相反。