Spring 如何解决 Bean 循环依赖

发布于:2024-05-23 ⋅ 阅读:(32) ⋅ 点赞:(0)

循环依赖解释

bean A 属性注入时依赖bean B ,并且bean B属性注入时也依赖bean A ,造成 bean A 和bean B 都无法完成初始化问题,形成了闭环。

注意

项目中存在Bean的循环依赖,是Bean对象职责划分不明确、代码质量不高的表现,如果存在大量的Bean之间循环依赖,那么代码的整体设计也就越来越糟糕。所以SpringBoot在后续的版本中终于受不了这种滥用,默认把循环依赖给禁用了!从2.6版本开始,如果你的项目里还存在循环依赖,SpringBoot将拒绝启动!

spring 如何解决循环依赖的?

Spring解决循环依赖的核心思想在于提前曝光,使用三级缓存进行提前曝光。

使用三级缓存去解决的。三个Map
一级缓存 缓存的完整的bean 即 完成了实例化和属性注入的bean
二级缓存 缓存的是半成品的bean 即完成了实例化但未属性注入的bean
三级缓存 缓存的是bean工厂:

解决过程

开始实例化一个bean-> 属性中依赖bean,向一级缓存中获取,发现没有-> 再向二级缓存中获取,发现没有
-> 从三级缓存中获取bean工厂,通过getObject() 方法,获取对象,放到二级缓存->当前bean引用二级缓存中的bean->最后再对二级缓存中的bean进行属性装配。

SpringBoot2.6.0及以上 具体解决方案

建议不要这么做,循环依赖的出现表明代码质量太低

最简单的方法在yaml或properties中配置spring.main.allow-circular-references=true 支持循环依赖即可

示例

TestBService 实现类 TestBServiceImpl 中 注入 TestService对象
TestService 实现类 TestServiceImpl 中注入 TestBService对象

@Service
public class TestBServiceImpl extends ServiceImpl<TestBMapper, TestB> 
implements TestBService {
    @Autowired
    private TestService testService;
}
@Service
public class TestServiceImpl extends ServiceImpl<TestAMapper, TestA> 
implements TestService {
    @Autowired
    private TestBService testBservice;
}

在 application.yml 中

spring:
  main:
    ## 支持循环依赖
    allow-circular-references: true

参考 Spring循环依赖解决方案