Spring Bean 循环依赖

在Spring框架中,Bean的创建和管理是其核心功能之一。然而,在复杂的应用系统中,Bean之间可能会形成循环依赖(Circular Dependency),这种情况如果不加以妥善处理,将会导致Spring容器在初始化时抛出异常。本文将深入探讨Spring Bean循环依赖的概念、Spring的解决机制以及我们如何在开发中避免或处理循环依赖。

什么是循环依赖?

循环依赖指的是两个或多个Bean之间通过构造函数、Setter方法或字段注入相互依赖,形成一个闭环。例如,Bean A依赖于Bean B,同时Bean B又依赖于Bean A,这就构成了一个典型的循环依赖。

常见的循环依赖场景

  • 构造函数注入:最容易导致循环依赖的注入方式,因为构造函数是在Bean完全初始化之前调用的,如果此时Bean A需要注入Bean B,而Bean B的初始化又需要Bean A,就会陷入死循环。
  • Setter方法注入:相对构造函数注入而言,Setter方法注入可以通过延迟注入的方式解决循环依赖问题。
  • 字段注入:字段注入的处理方式与Setter方法类似,但通常不推荐使用,因为它破坏了依赖的明确性和可读性。

Spring如何解决循环依赖?

三级缓存

Spring容器通过三级缓存机制解决了基于Setter方法的单例Bean的循环依赖问题。这三级缓存分别是:

  1. 一级缓存(SingletonObjects):存储完全初始化好的Bean,即所有依赖注入都完成的Bean。
  2. 二级缓存(EarlySingletonObjects):存储早期暴露的Bean对象,这些对象已经完成了实例化,但尚未进行属性填充(即依赖注入未完成)。
  3. 三级缓存(SingletonFactories):存储的是ObjectFactory,用于生成Bean的早期引用,以便在需要时能够获取到Bean的早期实例(尚未填充依赖)。

当Spring容器检测到循环依赖时,它会利用三级缓存来提前暴露Bean的早期引用,从而解决依赖注入问题。

流程简述

  1. 当Spring容器需要创建Bean A时,会先检查一级缓存中是否已存在Bean A的实例,如果不存在,则继续。
  2. 接着,Spring会尝试创建Bean A的实例,并将其ObjectFactory加入到三级缓存中。
  3. 随后,Spring在填充Bean A的依赖时,如果发现依赖的Bean B尚未创建,则开始创建Bean B。
  4. 如果Bean B也依赖于Bean A(即出现循环依赖),此时Spring会从三级缓存中获取Bean A的ObjectFactory,调用其getObject方法获取Bean A的早期引用,并将其注入到Bean B中。
  5. 接着,Spring完成Bean B的剩余初始化过程,并将其加入到二级缓存中。
  6. 当Bean B的初始化完成后,Spring回到Bean A的初始化流程,从二级缓存中获取Bean B的实例,完成Bean A的依赖注入和剩余初始化工作。
  7. 最后,将Bean A的实例加入到一级缓存中,供后续使用。
相关推荐
二月夜8 小时前
剖析Java正则表达式回溯问题
java·正则表达式
xuhaoyu_cpp_java8 小时前
项目学习(三)分页查询
java·经验分享·笔记·学习
程序员二叉9 小时前
【Java】集合面试全套精讲|HashMap/ArrayList高频考点完整版
java·面试·哈希算法
cfm_29149 小时前
JVM GC垃圾回收初步了解
java·开发语言·jvm
心之伊始9 小时前
LangChain4j RAG 实战:Java 后端如何把本地文档接入 Embedding 检索链路
java·架构·源码分析·csdn
许彰午10 小时前
17_synchronized关键字深度解析
java·开发语言
Xzh042311 小时前
AI Agent 学习路线(Java 后端方向)
java·人工智能·学习
艾利克斯冰12 小时前
Java 设计模式-行为型模式(更新中)
java·开发语言·设计模式
倒霉蛋小马12 小时前
Java新特性:record关键字
java·开发语言
折哥的程序人生 · 物流技术专研12 小时前
《Java 100 天进阶之路》第95篇:消息队列基础(RocketMQ/Kafka)(2026版)
java·面试·kafka·rocketmq·java-rocketmq·求职招聘