使用@Lazy解决循环依赖问题

  • 现象
  • 问题
    • 探索循环依赖产生的原因
  • 破除循环依赖
  • @Lazy解决循环依赖的方式
  • 总结

现象

现在有两个Bean,一个叫beanA,一个叫beanBbeanA通过构造器依赖beanBbeanB通过 @Autowrited依赖beanA

  1. BeanA.java

    @Component
    public class BeanA {private final BeanB beanB;public BeanA(BeanB beanB) {this.beanB = beanB;}
    }
    
  2. BeanB.java
    @Component
    public class BeanB {@Autowiredprivate BeanA beanA;}
    

问题

上面的这两个Bean在启动时会被Spring提示循环依赖,服务启动失败。

探索循环依赖产生的原因

首先,我们先来探究一下这是一个什么样的循环依赖:

  1. Spring通过AbstractAutowireCapableBeanFactory#createBeanInstance创建BeanA的实例对象
  2. BeanA没有默认的构造器,也没有被@Autowrited的修饰的构造,所以Spring会选择带有BeanB的构造器来实例化BeanA
  3. Spring开始实例化BeanBBeanB直接使用默认构造器实例化
  4. 实例化完成后,开始对BeanB执行AbstractAutowireCapableBeanFactory.populateBean,这时会由AutowiredAnnotationBeanPostProcessor来处理BeanB上的@Autowired注解。
  5. 由于BeanB @Autowired了BeanA,所以此时BeanB需要BeanA的实例来完成自己的依赖注入。
  6. 但是,此时BeanA已经开始实例化,但是还没有实例化完成(因为需要构造器注入BeanB
  7. 所以,就产生了循环依赖

破除循环依赖

那么要如何破除循环依赖呢?常见的办法有两种:

  1. 修改代码逻辑
    1. 从逻辑上进行整改,从而避免循环依赖的产生
    2. 不要使用构造器依赖,至少让bean可以被实例化
  2. 使用代理

使用 @Lazy 其实用的就是代理的方式来解决循环依赖的。

@Lazy解决循环依赖的方式

接下来我们debug看下为什么@Lazy能解决循环依赖

  1. 在创建beanA时,Spring依旧找到了带有BeanB的构造器
  2. Spring依然需要实例化一个BeanB出来,但是因为BeanA的构造器上写了 @Lazy,所以SpringBeanB创建了一个代理,并返回了。
  3. 接下来BeanB正常进行BeanB的初始化,当处理BeanB@Autowired BeanA时,由于BeanA已经创建完毕,所以BeanB也就可以正常创建了。
  4. 因为BeanA中的beanB其实是一个BeanB的代理,所以 beanA.getBeanB() 一定和beanB不是一个对象
  5. 但是 beanA.getBeanB().getBeanA() 却和beanA是同一个对象
  6. 这是因为在执行代理对象的getBeanA()时,会触发TargetSourcegetTarget()方法,从而返回真正的beanB

    所以beanA.getBeanB().getBeanA()和beanA指向的是同一个对象

总结

  1. 其实在SpringBoot 2.6.0之后Spring官方已经不建议循环依赖了,出现循环依赖还是最好从编码层面做解耦比较好。
  2. 如果项目比较复杂,解耦不易的话,可以采用 @Lazy的方式解决一部分循环依赖的问题。但是要注意 @Lazy会使用代理,用代理有用代理的坑,比如CGLIB代理模式下不能直接访问属性、final和private的方法不能代理等。

使用@Lazy解决循环依赖问题相关推荐

  1. Spring如何解决循环依赖问题

    一.循环依赖问题全景图 二.什么是循环依赖问题? 1.什么是循环依赖: 类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生. 比如下图中A类依赖了B类,B类依赖了C类,而最后C类又依赖了A类, ...

  2. Spring 是如何解决循环依赖的?

    1.由同事抛的一个问题开始 最近项目组的一个同事遇到了一个问题,问我的意见,一下子引起的我的兴趣,因为这个问题我也是第一次遇到.平时自认为对spring循环依赖问题还是比较了解的,直到遇到这个和后面的 ...

  3. spring:我是如何解决循环依赖的?

    1.由同事抛的一个问题开始 最近项目组的一个同事遇到了一个问题,问我的意见,一下子引起的我的兴趣,因为这个问题我也是第一次遇到.平时自认为对spring循环依赖问题还是比较了解的,直到遇到这个和后面的 ...

  4. 框架源码专题:Spring是如何解决循环依赖的?

    文章目录 1.什么是循环依赖? 2.解决循环依赖思路 3. 使用了三级缓存还有什么问题?怎么解决的? 4. 手写伪代码解决缓存依赖 5. 二级缓存能否解决循环依赖,三级缓存存在的意义 6. Sprin ...

  5. Spring是如何解决循环依赖的

    在关于Spring的面试中,我们经常会被问到一个问题,就是Spring是如何解决循环依赖的问题的.这个问题算是关于Spring的一个高频面试题,因为如果不刻意研读,相信即使读过源码,面试者也不一定能够 ...

  6. 什么是循环依赖?Spring如何解决循环依赖?

    1. Spring创建代理原理 1.1 ProxyFactory类 第一步:创建一个基础SpringBoot项目 <!--web--> <dependency><grou ...

  7. Spring三级缓存解决循环依赖

    1. 前言 循环依赖:就是N个类循环(嵌套)引用. 通俗的讲就是N个Bean互相引用对方,最终形成闭环.用一副经典的图示可以表示成这样(A.B.C都代表对象,虚线代表引用关系): 其实可以N=1,也就 ...

  8. what?spring已经解决循环依赖了,为啥还报循环依赖错误?

    前言 spring中的循环依赖及三层map解决方案,八股文中重灾区,强如小伙伴们或许一字一句倒背如流了,当年的我也是如此,然而现实狠狠给了我一巴掌,报错虽迟但到 报错一: The dependenci ...

  9. 闷棍暴打面试官 Spring源码系列: (一) Spring 如何解决循环依赖

    前言 初夏时节, 时间: AM 7.30分左右, 空无一人的健身房里,一个硕大的身体在跑步机上扭动着, 不一会头上便挥汗如雨, 他嘴上还不时嘀咕着 "循环依赖,单例模式,Bean的定位加载注 ...

  10. Spring是如何解决循环依赖的?

    1.案发情况 @Service public class TestService1 {@Autowiredprivate TestService2 testService2;@Asyncpublic ...

最新文章

  1. OpenCV(十八)霍夫变换(直线、线段与圆检测)
  2. JavaScript_下_Dom
  3. 面试必考之http状态码有哪些
  4. Xcode10新变化
  5. 数据中心的变化需要更多有效冷却方式
  6. CentOS 6.4 配置LAMP 环境 与安装 phpmyadmin
  7. PWN-PRACTICE-BUUCTF-18
  8. leetCode-995:K 连续位的最小翻转次数
  9. 位带操作全解释,个人觉得不错就转过来理解下
  10. SpringBoot配置RestTemplate的代理和超时时间
  11. Hbase与zookeeper
  12. 数百台浪潮服务器支撑中石油油品加工生产系统
  13. matlab画图线形
  14. 估值模型不适用_十年十倍!绝对估值法是如何引领巴菲特买入可口可乐的?
  15. 拍牌系统改版html5,开启上海拍牌的日子,有点玩人的系统,一会快一会慢
  16. EPC项目设计界面管理研究——以上海国际金融中心项目为例
  17. 恶意代码分析平台Truman相关资料
  18. 怎么解决win10以太网无有效ip
  19. 浅谈安科瑞无线测温系统在生物制药工厂中的应用
  20. 对抗生成神经网络-GAN通俗理解

热门文章

  1. 【离散数学笔记】逻辑运算之吸收律
  2. 程序员培训班出来之后,有可能向更高的层次爬升么?
  3. UEFI开发学习3 - 创建UEFI程序
  4. spring cloud 解决问题
  5. 高可用、高可扩展的原生WebView通信架构的思考
  6. E_Groundhog Chasing Death(不错的数论)
  7. 从代数结构上理解数集的分类
  8. 微信应用架构!!-----管理配置篇
  9. Elasticsearch Nested类型
  10. “三位一体”新驱动,基因检测行业走向交叉应用