使用@Lazy解决循环依赖问题
使用@Lazy解决循环依赖问题
- 现象
- 问题
- 探索循环依赖产生的原因
- 破除循环依赖
- @Lazy解决循环依赖的方式
- 总结
现象
现在有两个Bean,一个叫beanA
,一个叫beanB
,beanA
通过构造器依赖beanB
,beanB
通过 @Autowrited依赖beanA
:
- BeanA.java
@Component public class BeanA {private final BeanB beanB;public BeanA(BeanB beanB) {this.beanB = beanB;} }
- BeanB.java
@Component public class BeanB {@Autowiredprivate BeanA beanA;}
问题
上面的这两个Bean在启动时会被Spring提示循环依赖,服务启动失败。
探索循环依赖产生的原因
首先,我们先来探究一下这是一个什么样的循环依赖:
- Spring通过
AbstractAutowireCapableBeanFactory#createBeanInstance
创建BeanA
的实例对象 BeanA
没有默认的构造器,也没有被@Autowrited
的修饰的构造,所以Spring会选择带有BeanB
的构造器来实例化BeanA
- Spring开始实例化
BeanB
,BeanB
直接使用默认构造器实例化 - 实例化完成后,开始对
BeanB
执行AbstractAutowireCapableBeanFactory.populateBean
,这时会由AutowiredAnnotationBeanPostProcessor
来处理BeanB
上的@Autowired
注解。 - 由于BeanB @Autowired了BeanA,所以此时
BeanB
需要BeanA
的实例来完成自己的依赖注入。 - 但是,此时
BeanA
已经开始实例化,但是还没有实例化完成(因为需要构造器注入BeanB
) - 所以,就产生了循环依赖
破除循环依赖
那么要如何破除循环依赖呢?常见的办法有两种:
- 修改代码逻辑
1. 从逻辑上进行整改,从而避免循环依赖的产生
2. 不要使用构造器依赖,至少让bean可以被实例化 - 使用代理
使用 @Lazy 其实用的就是代理的方式来解决循环依赖的。
@Lazy解决循环依赖的方式
接下来我们debug看下为什么@Lazy
能解决循环依赖
- 在创建
beanA
时,Spring依旧找到了带有BeanB
的构造器
- Spring依然需要实例化一个
BeanB
出来,但是因为BeanA
的构造器上写了 @Lazy,所以Spring为BeanB
创建了一个代理,并返回了。
- 接下来
BeanB
正常进行BeanB
的初始化,当处理BeanB
的 @Autowired BeanA时,由于BeanA
已经创建完毕,所以BeanB
也就可以正常创建了。 - 因为
BeanA
中的beanB
其实是一个BeanB
的代理,所以 beanA.getBeanB() 一定和beanB不是一个对象
- 但是 beanA.getBeanB().getBeanA() 却和beanA是同一个对象
- 这是因为在执行代理对象的
getBeanA()
时,会触发TargetSource的getTarget()
方法,从而返回真正的beanB
所以beanA.getBeanB().getBeanA()和beanA指向的是同一个对象。
总结
- 其实在SpringBoot 2.6.0之后Spring官方已经不建议循环依赖了,出现循环依赖还是最好从编码层面做解耦比较好。
- 如果项目比较复杂,解耦不易的话,可以采用 @Lazy的方式解决一部分循环依赖的问题。但是要注意 @Lazy会使用代理,用代理有用代理的坑,比如CGLIB代理模式下不能直接访问属性、final和private的方法不能代理等。
使用@Lazy解决循环依赖问题相关推荐
- Spring如何解决循环依赖问题
一.循环依赖问题全景图 二.什么是循环依赖问题? 1.什么是循环依赖: 类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生. 比如下图中A类依赖了B类,B类依赖了C类,而最后C类又依赖了A类, ...
- Spring 是如何解决循环依赖的?
1.由同事抛的一个问题开始 最近项目组的一个同事遇到了一个问题,问我的意见,一下子引起的我的兴趣,因为这个问题我也是第一次遇到.平时自认为对spring循环依赖问题还是比较了解的,直到遇到这个和后面的 ...
- spring:我是如何解决循环依赖的?
1.由同事抛的一个问题开始 最近项目组的一个同事遇到了一个问题,问我的意见,一下子引起的我的兴趣,因为这个问题我也是第一次遇到.平时自认为对spring循环依赖问题还是比较了解的,直到遇到这个和后面的 ...
- 框架源码专题:Spring是如何解决循环依赖的?
文章目录 1.什么是循环依赖? 2.解决循环依赖思路 3. 使用了三级缓存还有什么问题?怎么解决的? 4. 手写伪代码解决缓存依赖 5. 二级缓存能否解决循环依赖,三级缓存存在的意义 6. Sprin ...
- Spring是如何解决循环依赖的
在关于Spring的面试中,我们经常会被问到一个问题,就是Spring是如何解决循环依赖的问题的.这个问题算是关于Spring的一个高频面试题,因为如果不刻意研读,相信即使读过源码,面试者也不一定能够 ...
- 什么是循环依赖?Spring如何解决循环依赖?
1. Spring创建代理原理 1.1 ProxyFactory类 第一步:创建一个基础SpringBoot项目 <!--web--> <dependency><grou ...
- Spring三级缓存解决循环依赖
1. 前言 循环依赖:就是N个类循环(嵌套)引用. 通俗的讲就是N个Bean互相引用对方,最终形成闭环.用一副经典的图示可以表示成这样(A.B.C都代表对象,虚线代表引用关系): 其实可以N=1,也就 ...
- what?spring已经解决循环依赖了,为啥还报循环依赖错误?
前言 spring中的循环依赖及三层map解决方案,八股文中重灾区,强如小伙伴们或许一字一句倒背如流了,当年的我也是如此,然而现实狠狠给了我一巴掌,报错虽迟但到 报错一: The dependenci ...
- 闷棍暴打面试官 Spring源码系列: (一) Spring 如何解决循环依赖
前言 初夏时节, 时间: AM 7.30分左右, 空无一人的健身房里,一个硕大的身体在跑步机上扭动着, 不一会头上便挥汗如雨, 他嘴上还不时嘀咕着 "循环依赖,单例模式,Bean的定位加载注 ...
- Spring是如何解决循环依赖的?
1.案发情况 @Service public class TestService1 {@Autowiredprivate TestService2 testService2;@Asyncpublic ...
最新文章
- OpenCV(十八)霍夫变换(直线、线段与圆检测)
- JavaScript_下_Dom
- 面试必考之http状态码有哪些
- Xcode10新变化
- 数据中心的变化需要更多有效冷却方式
- CentOS 6.4 配置LAMP 环境 与安装 phpmyadmin
- PWN-PRACTICE-BUUCTF-18
- leetCode-995:K 连续位的最小翻转次数
- 位带操作全解释,个人觉得不错就转过来理解下
- SpringBoot配置RestTemplate的代理和超时时间
- Hbase与zookeeper
- 数百台浪潮服务器支撑中石油油品加工生产系统
- matlab画图线形
- 估值模型不适用_十年十倍!绝对估值法是如何引领巴菲特买入可口可乐的?
- 拍牌系统改版html5,开启上海拍牌的日子,有点玩人的系统,一会快一会慢
- EPC项目设计界面管理研究——以上海国际金融中心项目为例
- 恶意代码分析平台Truman相关资料
- 怎么解决win10以太网无有效ip
- 浅谈安科瑞无线测温系统在生物制药工厂中的应用
- 对抗生成神经网络-GAN通俗理解