例如:类A需要通过构造函数注入的类B实例,类B需要通过构造函数注入的类A实例。如果将类A和类B配置为相互注入的bean,那么Spring IoC容器将在运行时检测到此循环引用,并抛出BeanCurrentlyInCreationException。
一种可能的解决方案是编辑由setter而不是构造器配置的一些类的源代码。或者,避免构造函数注入,只使用setter注入。换句话说,尽管不建议使用setter注入配置循环依赖项。
与典型的情况(没有循环依赖项)不同的是,Bean A和bean B之间的循环依赖项强制在完全初始化自身之前将一个bean注入另一个bean(典型的鸡和蛋的场景)。
您通常可以相信Spring会做正确的事情。它在容器装载时检测配置问题,例如对不存在的bean和循环依赖项的引用。在实际创建bean时,Spring尽可能晚地设置属性并解析依赖关系。这意味着,如果在创建该对象或其依赖项时出现问题,那么在以后请求对象时,正确加载的Spring容器可以生成异常——例如,bean由于丢失或无效属性而抛出异常。某些配置问题可能会延迟可见性,这就是为什么ApplicationContext实现在默认情况下预实例化单例bean。
在实际需要这些bean之前先花一些时间和内存来创建它们,在创建ApplicationContext时(而不是稍后),您会发现配置问题。您仍然可以覆盖这个默认行为,以便单例bean能够惰性地初始化,而不是被预先实例化。问题
如果不存在循环依赖项,当一个或多个协作bean被注入到依赖bean中时,每个协作bean在被注入到依赖bean之前都被完全配置好了。这意味着,如果bean A依赖于Bean B,那么在调用bean A上的setter方法之前,Spring IoC容器已经完全配置了Bean B。换句话说,bean被实例化(如果它不是一个预先实例化的单例对象),它的依赖关系被设置,相关的生命周期方法(例如配置的init方法或InitializingBean回调方法)被调用。
Examples of Dependency Injection下面的示例将基于xml的配置元数据用于基于setter的DI。Spring XML配置文件的一小部分指定了一些bean定义,如下所示:
<bean> <!-- setter injection using the nested ref element --> <property> <ref bean="anotherExampleBean"/> </property> <!-- setter injection using the neater ref attribute --> <property ref="yetAnotherBean"/> <property value="1"/> </bean> <bean/> <bean/>下面的例子显示了相应的ExampleBean类:
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public void setBeanOne(AnotherBean beanOne) { this.beanOne = beanOne; } public void setBeanTwo(YetAnotherBean beanTwo) { this.beanTwo = beanTwo; } public void setIntegerProperty(int i) { this.i = i; } }在前面的示例中,声明setter以匹配XML文件中指定的属性。下面的示例使用基于构造函数的DI:
<bean> <!-- constructor injection using the nested ref element --> <constructor-arg> <ref bean="anotherExampleBean"/> </constructor-arg> <!-- constructor injection using the neater ref attribute --> <constructor-arg ref="yetAnotherBean"/> <constructor-arg type="int" value="1"/> </bean> <bean/> <bean/>下面的例子显示了相应的ExampleBean类:
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public ExampleBean( AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { this.beanOne = anotherBean; this.beanTwo = yetAnotherBean; this.i = i; } }bean定义中指定的构造函数参数用作ExampleBean的构造函数的参数。
现在考虑这个例子的一个变体,在这个例子中,Spring不是使用构造函数,而是调用静态工厂方法来返回对象的实例:
<bean factory-method="createInstance"> <constructor-arg ref="anotherExampleBean"/> <constructor-arg ref="yetAnotherBean"/> <constructor-arg value="1"/> </bean> <bean/> <bean/>下面的例子显示了相应的ExampleBean类:
public class ExampleBean { // a private constructor private ExampleBean(...) { ... } // a static factory method; the arguments to this method can be // considered the dependencies of the bean that is returned, // regardless of how those arguments are actually used. public static ExampleBean createInstance ( AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { ExampleBean eb = new ExampleBean (...); // some other operations... return eb; } }