Spring 的循环依赖

在 Spring 中,循环依赖是指两个或多个 Bean 相互依赖,导致在创建过程中出现了依赖死锁的问题。为了解决循环依赖,Spring 引入了三级缓存机制。了解为什么需要三级缓存机制,首先要明白循环依赖是如何发生的,以及两级缓存为什么不足够。

一、循环依赖是什么?

假设有两个 Bean AB

  • A 依赖于 B
  • B 依赖于 A

如果没有缓存机制,Spring 在创建 A 时会发现它需要 B,于是去创建 B,但在创建 B 时又发现需要 A,这时就会产生循环依赖,最终导致栈溢出或抛出异常。

二、三级缓存机制

Spring 使用三级缓存(三级依赖处理机制)来解决循环依赖问题,分别是:

  1. 一级缓存singletonObjects,用于存储完全初始化好的单例对象。

    • 完全初始化后的 Bean 会放入一级缓存中,表示该 Bean 已经准备好可以使用了。
  2. 二级缓存earlySingletonObjects,用于存储提前暴露的 Bean,主要是尚未完成依赖注入但已经实例化的 Bean。

    • 这个缓存用于提前暴露尚未完成初始化的 Bean,防止循环依赖无法解决。通常情况下,如果某个 Bean 已经实例化但还没有完成后续的属性填充等操作,它会存放在这个缓存中。
  3. 三级缓存singletonFactories,用于存储 Bean 的 ObjectFactory(对象工厂),这个工厂提供对该 Bean 的代理对象(比如 AOP 代理对象)的创建逻辑。

    • 三级缓存的存在使得 Spring 可以在 Bean 创建的早期阶段将未完全初始化的 Bean 提供出来,尤其是代理对象。这样即使 Bean 还没有完成依赖注入,也能通过工厂获得它的一个早期引用。

三、为什么需要三级缓存?两级不行吗?

假如只使用一级缓存和二级缓存:

  • 一级缓存只存储已经完全初始化好的 Bean,显然无法解决循环依赖问题,因为 Bean 尚未完成初始化时无法放入一级缓存。
  • 二级缓存则存储提前暴露的 Bean,但这通常是直接的原始对象,而不是代理对象。如果应用了 AOP 或者需要创建代理对象的场景中,依赖的 Bean 如果在循环依赖中被提前暴露时,可能无法应用正确的代理。

三级缓存 允许通过 ObjectFactory 这种延迟加载的方式,在需要的时候创建早期引用,包括创建代理对象。这确保了即使在循环依赖中,Spring 也可以在合适的时间点创建完整的代理对象,而不是仅仅提供原始对象。

四、总结

三级缓存机制的关键点在于:

  • 二级缓存不能解决 Bean 代理的问题,特别是在涉及到 AOP 的情况下。
  • 三级缓存 通过引入 ObjectFactory,可以确保在代理场景下也能处理循环依赖,提前暴露还未完全初始化的代理对象。

因此,两级缓存不足以解决所有循环依赖问题,特别是在涉及到代理对象的情况下,三级缓存的机制显得非常必要。

相关推荐
c++之路4 分钟前
C++23概述
java·c++·c++23
专注API从业者1 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
摇滚侠1 小时前
DBeaver 导入数据库 导入 SQL 文件 MySQL 备份恢复
java·数据库·mysql
古城小栈1 小时前
从 cargo-whero 库中,找到提升 rust 的契机
开发语言·后端·rust
keep one's resolveY2 小时前
SpringBoot实现重试机制的四种方案
java·spring boot·后端
天空属于哈夫克32 小时前
企业微信API常见的错误和解决方案
java·数据库·企业微信
摇滚侠3 小时前
VMvare 虚拟机 Oracle19c 安装步骤,远程连接 Oracle19c,百度网盘安装包
java·oracle
梁萌3 小时前
idea报错找不到XX包的解决方法
java·intellij-idea·启动报错·缺少包
Agent产品评测局3 小时前
生产排期与MES/ERP系统打通,实操方法详解 —— 2026企业级智能体自动化选型与实战指南
java·运维·人工智能·ai·chatgpt·自动化
阿丰资源4 小时前
基于Spring Boot的电影城管理系统(直接运行)
java·spring boot·后端