spring如何解决循环依赖

Spring 解决循环依赖核心依靠:三级缓存 + 提前暴露早期半成品 Bean ,仅支持单例、构造器注入以外的场景。


一、什么是循环依赖

两个或多个 Bean 互相依赖:

java 复制代码
@Component
public class A {
  @Autowired
  private B b;
}

@Component
public class B {
  @Autowired
  private A a;
}

二、核心原理:三级缓存

Spring 容器维护三个 Map(三级缓存):

  1. singletonObjects(一级缓存)

    • 存放完全初始化好的单例 Bean
  2. earlySingletonObjects(二级缓存)

    • 存放实例化完成,但未填充属性、未初始化的早期 Bean
  3. singletonFactories(三级缓存)

    • 存放创建早期 Bean 的ObjectFactory,用于获取早期引用

三、解决流程(A ↔ B)

  1. 创建 A:实例化 A,将 A 的 ObjectFactory 放入三级缓存,暴露早期引用
  2. 填充 A 属性:发现依赖 B,去创建 B
  3. 创建 B:实例化 B,将 B 的 ObjectFactory 放入三级缓存
  4. 填充 B 属性:发现依赖 A,从缓存获取 A:
    • 先查一级缓存(无)
    • 查二级缓存(无)
    • 查三级缓存,拿到 A 的 ObjectFactory,获取早期 A 对象,放入二级缓存,并删除三级缓存
  5. B 完成属性填充 + 初始化,加入一级缓存
  6. 回到 A,拿到完整 B,完成 A 初始化,加入一级缓存

四、哪些情况无法解决

Spring 无法解决以下循环依赖,启动报错:

  1. 构造器注入循环依赖

    java 复制代码
    @Component
    public class A {
      // 构造器注入 B
      public A(B b) {}
    }
    
    @Component
    public class B {
      // 构造器注入 A
      public B(A a) {}
    }

    实例化时就互相依赖,无法提前暴露。

  2. 多例(prototype)Bean

    多例不进入缓存,每次创建新实例,无法缓存提前引用。

  3. 使用 @DependsOn 显式构成循环依赖。


五、无法解决时的方案

  1. 改用 setter / 字段注入(而非构造器)

  2. 使用 @Lazy 懒加载:

    java 复制代码
    @Component
    public class A {
      @Autowired
      @Lazy
      private B b;
    }
  3. 拆分子功能,解除循环依赖

  4. 使用 ApplicationContextAwareInitializingBean 手动获取依赖


六、总结

  • 默认支持:单例 + setter / 字段注入循环依赖
  • 核心手段:三级缓存提前暴露半成品 Bean
  • 不支持 :构造器注入、多例、@DependsOn 循环
  • 优化 :优先用 @Lazy 或重构代码解除循环
相关推荐
AlunYegeer27 分钟前
MyBatis 传参核心:#{ } 与 ${ } 区别详解(避坑+面试重点)
java·mybatis
少许极端39 分钟前
算法奇妙屋(四十)-贪心算法学习之路7
java·学习·算法·贪心算法
危笑ioi41 分钟前
helm部署skywalking链路追踪 java
java·开发语言·skywalking
夕除1 小时前
Mysql--15
java·数据库·mysql
smileNicky1 小时前
Linux 系列从多节点的catalina 日志中统计设备调用频次
java·linux·服务器
赵丙双1 小时前
spring boot 排除自动配置类的方式和原理
java·spring boot·自动配置
8Qi81 小时前
LeetCode热题100--45.跳跃游戏 II
java·算法·leetcode·贪心算法·编程
bilI LESS2 小时前
Spring Boot接收参数的19种方式
java·spring boot·后端
Chan162 小时前
MCP 开发实战:Git 信息查询 MCP 服务开发
java·开发语言·spring boot·git·spring·java-ee·intellij-idea
web前端进阶者2 小时前
Rust初学知识点快速记忆
开发语言·后端·rust