Ric*_*arn 71
在Spring参考手册介绍了循环依赖是如何解决的.首先实例化bean,然后相互注入.
考虑这个课程:
package mypackage;
public class A {
public A() {
System.out.println("Creating instance of A");
}
private B b;
public void setB(B b) {
System.out.println("Setting property b of A instance");
this.b = b;
}
}
Run Code Online (Sandbox Code Playgroud)
和类似的类B:
package mypackage;
public class B {
public B() {
System.out.println("Creating instance of B");
}
private A a;
public void setA(A a) {
System.out.println("Setting property a of B instance");
this.a = a;
}
}
Run Code Online (Sandbox Code Playgroud)
如果你有这个配置文件:
<bean id="a" class="mypackage.A">
<property name="b" ref="b" />
</bean>
<bean id="b" class="mypackage.B">
<property name="a" ref="a" />
</bean>
Run Code Online (Sandbox Code Playgroud)
使用此配置创建上下文时,您将看到以下输出:
Creating instance of A
Creating instance of B
Setting property a of B instance
Setting property b of A instance
Run Code Online (Sandbox Code Playgroud)
注意,当a注入时b,a尚未完全初始化.
Ste*_*n C 41
正如其他答案所说,Spring只是处理它,创建bean并根据需要注入它们.
其中一个后果是bean注入/属性设置可能以与XML布线文件似乎暗示的顺序不同的顺序发生.因此,您需要注意,您的属性设置器不会执行依赖于已调用的其他setter的初始化.处理这个问题的方法是将bean声明为实现InitializingBean接口.这需要您实现该afterPropertiesSet()方法,这是您进行关键初始化的地方.(我还包括用于检查实际已设置重要属性的代码.)
jon*_*ejj 18
在我正在使用的代码库(100万+代码行)中,我们遇到了启动时间长,大约60秒的问题.我们得到了12000+ FactoryBeanNotInitializedException.
我所做的是在AbstractBeanFactory#doGetBean中设置一个条件断点
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
Run Code Online (Sandbox Code Playgroud)
它在哪里destroySingleton(beanName)我用条件断点代码打印异常:
System.out.println(ex);
return false;
Run Code Online (Sandbox Code Playgroud)
显然,当FactoryBean涉及循环依赖图时会发生这种情况.我们通过实现ApplicationContextAware和 InitializingBean并手动注入bean 来解决它.
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class A implements ApplicationContextAware, InitializingBean{
private B cyclicDepenency;
private ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
ctx = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
cyclicDepenency = ctx.getBean(B.class);
}
public void useCyclicDependency()
{
cyclicDepenency.doSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
这将启动时间缩短到大约15秒.
因此,不要总是认为spring可以很好地为您解决这些问题.
出于这个原因,我建议使用AbstractRefreshableApplicationContext #setAllowCircularReferences(false)禁用循环依赖关系解决,以防止将来出现许多问题.
小智 12
问题 - >
Class A {
private final B b; // must initialize in ctor/instance block
public A(B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
Run Code Online (Sandbox Code Playgroud)
//引起:org.springframework.beans.factory.BeanCurrentlyInCreationException:创建名为"A"的bean时出错:请求的bean当前正在创建:是否存在无法解析的循环引用?
解决方案1 - >
Class A {
private B b;
public A( ) { };
//getter-setter for B b
}
Class B {
private A a;
public B( ) { };
//getter-setter for A a
}
Run Code Online (Sandbox Code Playgroud)
解决方案2 - >
Class A {
private final B b; // must initialize in ctor/instance block
public A(@Lazy B b) { this.b = b };
}
Class B {
private final A a; // must initialize in ctor/instance block
public B(A a) { this.a = a };
}
Run Code Online (Sandbox Code Playgroud)
小智 6
Spring容器能够解析基于Setter的循环依赖关系,但在基于构造函数的循环依赖关系中提供运行时异常BeanCurrentlyInCreationException.在基于Setter的循环依赖的情况下,IOC容器处理它与典型情况不同,在典型情况下它将在注入之前完全配置协作bean.例如,如果Bean A在Bean C上依赖Bean B和Bean B,则容器在将C注入B之前完全初始化C,并且一旦B完全初始化,它将被注入A.但是在循环依赖的情况下,在完全初始化之前,将豆子注入另一个.
假设A依赖于B,那么Spring将首先实例化A,然后实例化B,然后为B设置属性,然后将B设置为A。
但是,如果B也依赖于A怎么办?
我的理解是:Spring刚发现A已经被构造(构造函数执行),但是还没有完全初始化(并不是所有注入都完成了),嗯,它认为,没关系,A可以被完全初始化是可以容忍的,只要将其设置为-现在将A实例完全初始化为B。在B完全初始化之后,将其设置为A,最后,A现已完全启动。
换句话说,它只是提前将A暴露给B。
对于通过构造函数的依赖关系,Sprint只是抛出BeanCurrentlyInCreationException来解决此异常,请通过构造函数-arg方式将依赖于其他bean的bean的lazy-init设置为true。