当前位置: 代码网 > it编程>编程语言>Java > Springboot循环依赖的原因及解决

Springboot循环依赖的原因及解决

2025年05月07日 Java 我要评论
什么是循环依赖循环依赖(circular dependency)是指两个或多个 bean 相互直接或间接依赖,导致容器无法正常初始化这些 bean。@servicepublic class servi

什么是循环依赖

循环依赖(circular dependency) 是指两个或多个 bean 相互直接或间接依赖,导致容器无法正常初始化这些 bean。

@service
public class servicea {
    @autowired
    private serviceb serviceb; // servicea 依赖 serviceb
}

@service
public class serviceb {
    @autowired
    private servicea servicea; // serviceb 依赖 servicea
}

spring boot 基于 spring 框架,其循环依赖的处理机制与 spring 一致,但在 spring boot 2.6+ 版本中默认禁止了循环依赖(通过 spring.main.allow-circular-references=false)。 

产生循环依赖的原因

1.构造函数注入循环依赖

@service
public class servicea {
    private final serviceb serviceb;
    public servicea(serviceb serviceb) { // 构造函数注入
        this.serviceb = serviceb;
    }
}

@service
public class serviceb {
    private final servicea servicea;
    public serviceb(servicea servicea) { // 构造函数注入
        this.servicea = servicea;
    }
}
  • 直接报错:构造函数注入的循环依赖无法解决,容器启动时抛出 beancurrentlyincreationexception

2.setter/field 注入循环依赖

在spring中使用@autowired注解标签进行自动注入,如果不加以处理,会出现循环依赖问题 。

怎么解决循环依赖

在springboot2.5以前可以通过三级缓存解决单例 bean 的循环依赖问题。

缓存名称职责
singletonobjects存放完全初始化好的 bean(一级缓存)
earlysingletonobjects存放提前暴露的早期 bean(二级缓存)
singletonfactories存放 bean 的工厂对象(三级缓存)

以最初的servicea与serviceb为例,

  • 创建 servicea,通过工厂将其半成品引用存入三级缓存。

  • servicea 注入 serviceb,触发 serviceb 的创建。

  • 创建 serviceb,同样将其半成品引用存入三级缓存。

  • serviceb 注入 servicea 时,从三级缓存中获取 servicea 的早期引用,完成 serviceb 的初始化。

  • serviceb 初始化完成后,servicea 完成依赖注入,最终初始化。

 出现循环依赖之后的几个解决思路:

1.避免循环依赖(推荐)

  • 重构代码:将公共逻辑抽离到第三个 bean 中。

  • 使用接口或抽象类:通过面向接口编程解耦具体实现。

2. 允许循环依赖(临时方案)

在 application.properties 中显式允许循环依赖:

# spring boot 2.6+ 需要手动开启
spring.main.allow-circular-references=true

这种只适用于springboot版本在2.6以上的循环依赖被禁止的情形。 

3. 使用 @lazy 延迟加载

在其中一个依赖上添加 @lazy,延迟注入 bean 的初始化:

@service
public class servicea {
    @lazy
    @autowired
    private serviceb serviceb; // 延迟初始化 serviceb
}

4. 调整注入方式

 优先使用 setter/field 注入:避免构造函数注入导致的不可解循环依赖。

@service
public class servicea {
    private serviceb serviceb;
    
    @autowired
    public void setserviceb(serviceb serviceb) { // setter 注入
        this.serviceb = serviceb;
    }
}

 使用setter注入

循环依赖的局限性

  • 构造函数注入无法解决循环依赖:spring 容器在创建 bean 时需先完成构造函数调用,此时依赖的 bean 尚未初始化。

  • 原型(prototype)作用域的 bean:spring 不管理原型 bean 的完整生命周期,无法解决其循环依赖。

  • aop 代理问题:如果 bean 被 aop 代理(如 @async@transactional),可能导致循环依赖解决失败。

总结

spring boot 的循环依赖本质是 spring 框架的机制问题,解决核心在于:

  • 理解三级缓存的工作原理。

  • 优先通过代码设计避免循环依赖。

  • 必要时合理使用 @lazy 或调整注入方式。

 尽可能在设计之初就避免循环依赖

到此这篇关于springboot循环依赖的原因及解决的文章就介绍到这了,更多相关springboot循环依赖内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com