循环依赖bean的创建过程
假设需要创建两个bean,a
和b
,并出现循环依赖。这里a
和b
都应是单例的,注入方式为setter注入
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
假设Spring容器需要先创建a
,则将会执行下列流程
- 依次检查一级缓存
singletonObjects
、二级缓存earlySingletonObjects
、三级缓存singletonFactories
。由于是第一次获取a
,无法从缓存直接返回 - 实例化
a
对象 - 将可以获取
a
对象的单例工厂放进三级缓存singletonFactories
中 - 设置
a
对象的属性,此时发现需要依赖b
,则转向获取b
- 依次检查缓存,由于是第一次获取
b
,无法从缓存直接返回 - 实例化
b
对象 - 将可以获取
b
对象的单例工厂放进三级缓存singletonFactories
中 - 设置
b
对象的属性,此时发现需要依赖a
,则转向获取a
- 依次检查缓存,在三级缓存中发现并获取
a
。在三级缓存获取a
的时候,假如有对bean进行AOP处理,会在此时处理并返回一个代理对象,否则返回a
本身。在返回之前,会把这个返回的对象加入到二级缓存earlySingletonObjects
中,同时把相应的三级缓存删除。 - 将
a
设置到b
对象的属性中 - 继续
b
对象后续的创建过程,完整创建完b
对象后,b
对象将进入一级缓存singletonObjects
,并删除相应的三级缓存。且返回给a
对象设置属性使用 - 将
b
设置到a
对象的属性中 - 继续
a
对象后续的创建过程,a
存在于二级缓存,二级缓存中可能是已经进行AOP处理的代理对象,需要将这个代理对象放进一级缓存中,然后清除二级缓存
处理循环依赖的一些细节
- 非单例的bean无法解决循环依赖
- 构造器注入方式可能导致无法解决循环依赖,先创建的bean不能以构造器方式注入后创建的bean。先创建的bean还没放进三级缓存,就需要获取依赖的bean,导致创建过程死循环
- 常规的AOP处理在
BeanPostProcessor
的postProcessAfterInitialization
阶段。一般为AbstractAutoProxyCreator
的postProcessAfterInitialization
方法。只有在循环依赖出现的时候,才需要把AOP处理提前到从三级缓存取出的时候 - 二级缓存和三级缓存的设计是为了解决循环依赖的问题
- 三级缓存并不能提高性能,主要还是为了保持Spring原有的设计,在没有循环依赖的情况下,将AOP处理保留在
BeanPostProcessor
的postProcessAfterInitialization
阶段
PREVIOUSVue单文件组件基础结构
NEXTaxios发送请求参数