Spring中如何解决循环依赖,简单举个下面这样例子
- A类中注入了B类对象
- B类中注入了A类对象
如果是通过构造函数注入,那么在初始化时的时候会报循环注入。A初始化时B可能尚未初始化。
反之,如果是通过get set这种注入或者@Autowired 注入,并且是singelton(默认)而非prototype则不会报错。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。spring通过提前暴露一个单例工厂方法,从而使其他bean能引用到该bean。
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.containsKey(beanName)
&& this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
1.从源码中可以看出,A实例化时会去singletonsCurrentlyInCreation写入A,A中依赖B因此,需要实例化B,B中依赖A,因此需要实例A,而A之前已经在Increation,因此会报错。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiate the bean.
//.....
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// ......
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (singletonObject) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory objectFactory = this.singletonFactories.get(beanName);
if (objectFactory != null) {
singletonObject = objectFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT) ? singletonObject : null;
}
2.采用set方法时,Spring略有不同,A实例化时会将一个 A的实例引用写入objectFactory中。执行setB时去实例化B,B的setA调用getSingleton(A,true),因为A 实例还在创建中,会接着往下执行,最终通过objectFactory返回A的实例引用,之后删除factory,缓存A的引用。