- 构造器的方式
通过构造器参数注入,形成的循环依赖,无法解决,因为执行构造方法初始话之前会先将A放在正在创建的Bean池中,创建完成后移除,当A依赖于B ,B又依赖于A时,创建A时放在了正在创建Bean池中,需要B时创建B,将B放在了正在创建Bean池,而B需要A,此时A已经在正在创建Bean池中,所以会报错。
2.setter方式原型,prototype
prototype 每次getBean都会返回新的bean. 考虑线程安全和并发的时候 ,考虑使用prototype。
循环依赖情况下,prototype的,spring容器不进行缓存,无法提前暴露一个创建中的Bean.
3.setter方式单例。
三级缓存
一级缓存:已经初始化完成的bean 单例池
二级缓存:只实例化但是没有注入属性的bean 集合
三级缓存:工厂bean的缓存集合 (解决代理问题) 如果需要创建代理返回的代理对象,如果不需要代理返回的原始对象。
A依赖于B ,B依赖于A
getBean(A)-》从一级缓存中查找===》没有的话找二级 ==》没有的话找三级=》都没有创建A的实例==》
A的原始对象提前暴露放在三级缓存中
==》A填充属性时需要 B => 从一级缓存中查找===》没有的话找二级 ==》没有的话找三级=》都没有创建B的实例==》
B的原始对象提前暴露放在三级缓存中 ( 在B未初始化完成而有其他类需要B时执行三级缓存中 需要代理的话返回代理对象==》把B放在二级缓存中 )
==>B填充属性时需要 A=> 从一级缓存中查找===》没有的话找二级 ==》在三级缓存中找到A的引用。
==》 三级缓存中A 需要代理的话返回代理对象==》把A放在二级缓存中
==》B使用二级缓存中的A
==》初始化完成==》B进入一级缓存中。
==》A的填充完属性B ==》初始化完成 ==>A进入一级缓存中。
为什么使用第三级工厂缓存?
如果只有二级缓存的话,A创建的最后阶段可能创建代理,生成代理对象,而B中初始化已经完成,但是使用的是A的原始引用,导致不一致。
为什么不提前执行完代理逻辑,放入二级缓存中?
因为A在实例化完之后,并不知道是否有B依赖A,如果没有的话,A创建后期还是会再执行一遍扩展,导致执行重复。
网友评论