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的实例加入到一级缓存中,供后续使用。
相关推荐
禁默30 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood36 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Code哈哈笑39 分钟前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb421528742 分钟前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶43 分钟前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
zfoo-framework1 小时前
【jenkins插件】
java
风_流沙1 小时前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch
ProtonBase1 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
乐之者v2 小时前
leetCode43.字符串相乘
java·数据结构·算法