首先
为什么需要三级缓存(或者三级缓存中为什么是lambda表达式)
如果不放lambda表达式那就是放半成品的实例化对象,如果不涉及到代理,那就没问题。(A依赖B B依赖A )
- 实例化A
- 将半成品的实例化对象A放在缓存中
- 填充A的属性,发现A依赖B 实例化B
- 将半成品的实例化对象B放在缓存中
- 填充B的属性,发现B依赖A
- 从缓冲中获取A
- 初始化B完成 完整的B放在一级缓存
- A引入B 完成初始化 完整的A 放在一级缓存
至此, A和B都完成了依赖注入。没有问题。
如果A需要被代理,而Spring生成代理对象是在对象的初始化之后。如果将A的半成品实例化对象放在缓存中,而B实际需要的是A的代理对象,这就会有问题,所以lambda表达式必须要存在
其次
上面解释了为什么需要把lambda表达式放在缓存中,那么为什么需要二级缓存呢,这个问题更简单。如果 A 依赖BC BC同时也依赖A。B从缓冲中获取A(执行lambda表达式),C也从缓存中获取A(执行lambda表达式,每次执行表达式都会获取新的对象,这样也会有问题。
最后
如果ServiceA中有@Async, 项目启动会报错。
为什么呢?
因为B依赖A时,执行了A的lambda表达式会创建A的代理对象前,把对象放在earlyProxyReferences中,代表已经进行了aop操作,在执行A的初始化后续操作(BeanPostProcess.postProcessAfterInitialization),会校验earlyProxyReferences中是否执行过aop,如果执行过则不在执行。
而@Async的BeanPostProcess并不会判断,因此会再次执行创建代理对象,所以报对象冲突的异常。