完整文章内容可点击下方链接查看:
本篇不仅介绍了Spring循环依赖的原理,还详细解析了Spring不能支持的循环依赖场景与案例,并给出了解决建议与方案,以减少未来的弯路。
作者 | 刘斌(蔆素)
来源 | 阿里开发者公众号
背景
1、循环依赖异常信息
2、依赖关系
3、涉及基础知识
问题
1、什么是循环依赖?
2、为什么会产生循环依赖?
3、循环依赖有哪些场景?
4、Spring如何解决循环依赖的?
5、Spring为什么使用三级缓存?
6、Spring支持AOP循环依赖,为何还存在循环依赖异常?
7、Spring不支持的循环依赖场景及如何解决?
注:Spring启动流程与Bean创建初始化流程如不熟悉,自行补习,篇幅原因此处不做介绍
Spring循环依赖
1、什么是循环依赖
2、核心概念
1、什么情况下出现循环依赖
2、循环依赖场景
3、三级缓存解决循环依赖
(1)、一级缓存
DefaultSingletonBeanRegistry
(2)、二级缓存
二级缓存(未初始化未填充属性提前暴露的Bean)
(3)、三级缓存
三级缓存(Bean创建时提供代理机会的Bean工厂缓存)
6、Spring为何不使用一级、二级缓存解决循环依赖
循环依赖产生在Bean创建时
三级缓存获取Bean
SmartInstantiationAwareBeanPostProcessor重点 -> APC之父
7、Spring支持动态代理循环依赖,为何还会出循环依赖异常?
(1)、相互依赖的Bean只有需要AOP或者动态代理时才有可能出现循环依赖异常
(2)、各别注解使用不当
(3)、存在多个AutoProxyCreator(APC),出现多层代理
spring默认保证一个容器中只能有一个Aop的APC,如过手动添加或者自定义会出现多个APC情况
AopConfigUtils
存在多个APC时,如存在循环依赖,此时触发之前放入三级缓存逻辑
从而触发多个APC的 getEarlyBeanReference
最终proxy2会被注入到依赖的Bean中,即例如:A-proxy2 注入到 B中存在多个多层代理情况,getEarlyBeanReference 没有问题,但是执行到初始化时
8、正常AOP代理为何没问
SmartInstantiationAwareBeanPostProcessor
解决方案
1、无需代理场景使用原始对象
2、@lazy解耦
DefaultListableBeanFactory#resolveDependency
3、抽取公共逻辑
案例(可直接运行)
1、@Repository案例分析
2、多AutoProxyCreator场景
总结
出现循环依赖其实反映代码结构设计上的问题,理论上应当将循环依赖进行分层,抽取公共部分,然后由各个功能类再去依赖公共部分。
但是在复杂代码中,各个service、manager类互相调用太多,总会一不小心出现一些类之间的循环依赖的问题。可有时候我们又发现在用Spring进行依赖注入时,虽然Bean之间有循环依赖,但是代码本身却大概率能很正常的work,似乎也没有任何bug。
很多敏感的同学心里肯定有些犯嘀咕,循环依赖这种触犯因果律的事情怎么能发生呢?没错,这一切其实都并不是那么理所当然。Spring已经为我们背负了太多,但绝不是偷懒的借口,还是应该规范设计,规范代码,尽量做到从根本上避免这种循环依赖的发生。
阿里云开发者社区,千万开发者的选择。百万精品技术内容、千节免费系统课程、丰富的体验场景、活跃的社群活动、行业专家分享交流,尽在:
温馨提示:答案为网友推荐,仅供参考