spring循环依赖
- what
- 实例化一个完整的bean主要分两步,实例化(调用构造器在堆内存中分配一块内存)和初始化(给属性赋值);
- ClassA中有ClassB属性,ClassB中有ClassA属性,导致在bean初始化填充属性时,导致循环依赖
- when
- 在bean生成周期的属性填充阶段(populateBean)
- why
- ClassA中有ClassB属性,ClassB中有ClassA属性,导致在bean初始化填充属性时,导致循环依赖
- how(如何解决)
- 使用三级缓存,DefaultSingletonBeanRegistry
-
缓存 存储的内容 作用 备注 一级缓存
成品对象 二级缓存 半成品对象,只做了实例化(在堆内存中分配了空间),未做初始化 三级缓存 lambda表达式 获取源对象或代理对象 AbstractAutowireCapableBeanFactory#doGetBean中
getEarlyBeanReference逻辑(生成代理对象或原对象)
QA:
q:可以只用一个map集合吗?
a:可以,但不优雅,需要区分一个实例的半成品和成品,通过在key上加前缀等方案做区分,代码不友好;
q: 只用两级缓存,可以吗?
a:如果没有动态代理,可以;
q:为什么有动态代理就需要第三级缓存?
a:动态代理的生成在bean生命周期的BeanPostProcessor的postProcessAfterInitialization方法中实现,而bean的属性填充在此之前,所以此时并没有创建出对应的代理对象(如果需要代理对象的话); 所以需要提前生成代理对象,但spring无法感知是否需要生成代理对象(是由业务代码决定的),所以需要的属性填充之前唯一确定是原始对象还是代理对象,而属性的赋值时间也不可控,所有通过lambda表达式类似回调的机制在属性填充时确定是原对象还是代理对象。