1. 产生的条件
在容器启动时,创建非懒加载的单例bean A,执行A的生命周期
- 实例化A
- 填充A的b属性-->查单例池-->没有则创建B,执行B的生命周期
- 实例化B
- 填充B的a属性-->查单例池-->没有则创建A... 此处产生循环依赖
- 初始化前,初始化,初始化后
- 放入单例池
2.打破循环依赖:引入二级缓存
- 实例化A--> 放入二级缓存
- 填充A的b属性
- 实例化B
- 填充B的a属性-->查单例池-->查二级缓存有,打破循环
虽然这里B对象填充的a属性暂时没有经过完整的生命周期,但是对象引用的是同一个地址,后续等到A对象处理完生命周期,B对象的a属性自然就是完整的bean,所以不是主要的问题
3. 初始化前,初始化,初始化后
4. 放入单例池
3.上述主要存在的问题:如果A创建的是AOP代理对象,那么创建B时属性注入的A属性应该也要是代理对象
如何解决:只有出现循环依赖,才让bean提前进行AOP得到代理对象。不能违反
- 标记A正在创建
- 实例化A
- 填充A的b属性
- 标记B正在创建
- 实例化B
- 填充B的a属性-->查单例池-->判断如果A正在创建-->查二级缓存-->判断A是否需要AOP?代理对象 : 原始对象 -->放入二级缓存
如果B对象注入属性c,创建对象C时也依赖了a属性,根据单例的设计原则,避免重复创建代理对象,所以要先查二级缓存
4. 初始化前,初始化,初始化后
5. A放入单例池
4.原始对象从哪里来?难道方法逐层传递?Spring采用函数接口编程
如何解决:只有出现循环依赖,才让bean提前进行AOP得到代理对象。不能违反
- 标记A正在创建
- 实例化A-->放入三级缓存
- 填充A的b属性
- 标记B正在创建
- 实例化B
- 填充B的a属性-->查单例池-->判断如果A正在创建-->查二级缓存-->三级缓存:执行lambda表达式创建代理对象或者返回原始对象-->放入二级缓存
1. 三级缓存:<beanname,lambda<A原始对象>>
2. 执行lamb表达式:调用后置处理器的回调方法,还会向earlyProxyReferences添加缓存标记。因为bean提前进行过AOP,后续执行初始化后的回调方法会用来判断,不需要再重复进行AOP
4. 初始化前,初始化,初始化后
5. A放入单例池