spring的循环依赖

 

1 单例 bean 构造器参数循环依赖(⽆法解决)
prototype 原型 bean循环依赖(⽆法解决)对于原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过setXxx⽅法产⽣循环依赖,Spring都 会直接报错处理。 总结:Spring 不⽀持原型 bean 的循环依赖。

3 只能解决单例bean通过setXxx或者@Autowired进⾏循环依赖

spring获取bean的顺序是先1级缓存,没有就去2级缓存取,没有3级缓存取

三级缓存是在2.5.4版本才引入的,2.5.4之前的版本都只有一级和三级缓存

 

 

一级缓存-singletonObjects是用来存放就绪状态的Bean。保存在该缓存中的Bean所实现Aware子接口的方法已经回调完毕,自定义初始化方法已经执行完毕,也经过BeanPostProcessor实现类的postProcessorBeforeInitialization、postProcessorAfterInitialization方法处理;

二级缓存-earlySingletonObjects是用来存放早期曝光的Bean,一般只有处于循环引用状态的Bean才会被保存在该缓存中保存在该缓存中的Bean所实现Aware子接口的方法还未回调,自定义初始化方法未执行,也未经过BeanPostProcessor实现类的postProcessorBeforeInitialization、postProcessorAfterInitialization方法处理。如果启用了Spring AOP,并且处于切点表达式处理范围之内,那么会被增强,即创建其代理对象。

这里额外提一点,普通Bean被增强(JDK动态代理或CGLIB)的时机是在AbstractAutoProxyCreator实现的BeanPostProcessor的postProcessorAfterInitialization方法中,而处于循环引用状态的Bean被增强的时机是在AbstractAutoProxyCreator实现的SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法中。

三级缓存-singletonFactories是用来存放创建用于获取Bean的工厂类-ObjectFactory实例。在IoC容器中,所有刚被创建出来的Bean,默认都会保存到该缓存中

 

Bean在这三个缓存之间的流转顺序为(存在循环引用):

通过反射创建Bean实例。是单例Bean,并且IoC容器允许Bean之间循环引用,保存到三级缓存中。
当发生了循环引用时,从三级缓存中取出Bean对应的ObjectFactory实例,调用其getObject方法,来获取早期曝光Bean,从三级缓存中移除,保存到二级缓存中。
Bean初始化完成,生命周期的相关方法执行完毕,保存到一级缓存中,从二级缓存以及三级缓存中移除。
Bean在这三个缓存之间的流转顺序为(没有循环引用):

通过反射创建Bean实例。是单例Bean,并且IoC容器允许Bean之间循环引用,保存到三级缓存中。
Bean初始化完成,生命周期的相关方法执行完毕,保存到一级缓存中,从二级缓存以及三级缓存中移除。
简略流程图:

 

总结
通过以上分析,我们可以得知Bean在一级缓存、二级缓存、三级缓存中的流转顺序为:三级缓存->二级缓存->一级缓存。但是并不是所有Bean都会经历这个过程,例如对于原型Bean(Prototype),IoC容器不会将其保存到任何一个缓存中的,另外即便是单例Bean(Singleton),如果没有循环引用关系,也不会被保存到二级缓存中的。

参考链接:https://blog.csdn.net/m0_43448868/article/details/113578628

 小结

如果没有循环依赖的情况的话,一级缓存就可以搞定所有的情况,只需要在 bean 完全初始化好之后将其放入一级缓存即可。

但是一级缓存解决不了循环依赖的情况,所以,Spring 使用三级缓存来解决了循环依赖问题。

如果使用二级缓存的话,理论上是可行的,但是 Spring 选择了三级缓存来实现,让 bean 的创建流程更加符合常理,更加清晰明了。

相关推荐文档

Spring 为什么要用三级缓存来解决循环依赖问题呢?

原文链接:https://blog.csdn.net/wang489687009/article/details/120655156

posted @ 2022-03-30 15:47  不死码农  阅读(212)  评论(0编辑  收藏  举报