循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A依赖于B,B依赖于C,C⼜依赖于A。

注意,这⾥不是函数的循环调⽤,是对象的相互依赖关系。循环调⽤其实就是⼀个死循环,除⾮有终结条件。
Spring中循环依赖场景有:
其中,构造器的循环依赖问题⽆法解决,只能拋出
BeanCurrentlyInCreationException 异常,在解决属性循环依赖时,spring采⽤的是提前暴露对象的⽅法。
对于原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过
setXxx⽅法产⽣循环依赖,Spring都 会直接报错处理。
AbstractBeanFactory.doGetBean()⽅法:
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>)curVal).contains(beanName))));
}在获取bean之前如果这个原型bean正在被创建则直接抛出异常。原型bean在创建之前会进⾏标记这个
beanName正在被创建,等创建结束之后会删除标记
try {
//创建原型bean之前添加标记 beforePrototypeCreation(beanName);
//创建原型bean prototypeInstance = createBean(beanName, mbd, args);}finally {
//创建原型bean之后删除标记 afterPrototypeCreation(beanName);
}总结:Spring 不⽀持原型 bean 的循环依赖。
单例bean通过
setXxx或者
@Autowired进⾏循环依赖
Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前
Spring通过
setXxx或者
@Autowired⽅法解决循环依赖其实是通过提前暴露⼀个
ObjectFactory对象来完成的,简单来说ClassA在调⽤构造器完成对象初始化之后,在调⽤ClassA的
setClassB⽅法之前就把ClassA实例化的对象通过
ObjectFactory提前暴露到Spring容器中。
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");
}
//将初始化后的对象提前已ObjectFactory对象注⼊到容器中 addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}ClassA调⽤setClassB⽅法,Spring⾸先尝试从容器中获取ClassB,此时ClassB不存在Spring容器中。
Spring容器初始化ClassB,同时也会将ClassB提前暴露到Spring容器中
ClassB调⽤setClassA⽅法,Spring从容器中获取ClassA ,因为第⼀步中已经提前暴露了ClassA,因此可以获取到ClassA实例
ClassA通过spring容器获取到ClassB,完成了对象初始化操作。
这样ClassA和ClassB都完成了对象初始化操作,解决了循环依赖问题。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69964492/viewspace-2765336/ ,如需转载,请注明出处,否则将追究法律责任。