Spring的循环依赖及三级缓存

多个Bean之间相互依赖,形成一个闭环

两种注入方式对循环依赖的影响

构造器注入:容易造成无法解决的循环依赖,不推荐使用(If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.)
Setter 注入:推荐使用 setter 方式注入单例 bean
结论:我们 AB 循环依赖问题只要 A 的注入方式是 setter 且 singleton,就不会有循环依赖问题
只有单例的bean会通过三级缓存提前暴露来解决循环依赖的问题,因为单例的时候只有一份,随时复用,那么就放到缓存里面 ,所以一定要有一个缓存保存它的早期对象作为死循环的出口。而多例的bean,每次从容器中荻取都是—个新的对象,都会重新创建,所以非单例的bean是没有缓存的,不会将其放到三级缓存中。

第一级缓存:Map<String, Object> singletonObjects,也称成品单例池,常说的 Spring 容器就是指它,我们获取单例 bean 就是在这里面获取的,存放已经经历了完整生命周期的Bean对象。

第二级缓存:Map<String, Object> earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整,可以认为是半成品的 bean)。避免多重循环依赖的情况重复创建动态代理,放二级缓存如果有C也依赖了A那么就从二级缓存取,不用重新创建了。

第三级缓存:Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工厂,用于生产(创建)对象。

缓存是函数接口:通过lamda把方法传进去( 把Bean的实例和Bean名字传进去(aop创建) )
不会立即调: (如果在实例化后立 即调用的话:所有的aop不管bean是否循环依赖都会在实例化后创建proxy代理对象,对于正常Bean其实spring还是希望遵循生命周期在初始化创建动态代理,只能循环依赖才创建)
会在ABA (第二次getBean(A)才会去调用三级缓存(如果实现了aop才会创建动态代理,如果没有实现依然返回的Bean的实例) )
放入二级缓存(避免車复创建)
四大方法

getSingleton():从容器里面获得单例的bean,没有的话则会创建 bean
doCreateBean():执行创建 bean 的操作(在 Spring 中以 do 开头的方法都是干实事的方法)
populateBean():创建完 bean 之后,对 bean 的属性进行填充
addSingleton():bean 初始化完成之后,添加到单例容器池中,下次执行 getSingleton() 方法时就能获取到
注:关于三级缓存 Map<String, ObjectFactory<?>> singletonFactories的说明,singletonFactories 的 value 为 ObjectFactory 接口实现类的实例。ObjectFactory 为函数式接口,在该接口中定义了一个 getObject() 方法用于获取 bean,这也正是工厂思想的体现(工厂设计模式)

posted @ 2022-04-19 11:40  d-w  阅读(513)  评论(0编辑  收藏  举报