spring如何解决循环依赖问题的?

面试

对象先创建出来,但先不急着把它完全初始化好,而是先"提前曝光"一个半成品对象,让别的 Bean 先用。这个过程主要靠 三级缓存。

一级缓存:存放已经创建完成、可以直接使用的单例 Bean。

二级缓存:存放"提前曝光"的 Bean,也就是还没完全初始化好,但已经能先拿来用的对象。

三级缓存:存放一个工厂,用来生成"提前曝光对象"。为什么不直接放对象,而要放工厂?因为这样可以决定提前曝光的是原始对象,还是代理对象。

假设:

  • A 依赖 B
  • B 依赖 A

Spring 创建过程大致如下:

第一步:创建 A

Spring 发现 A 还没有,于是先实例化 A。

注意,这时候 A 只是被 new 出来了,属性还没注入完,还不是完整对象

然后 Spring 会把一个能获取 A 早期对象的工厂放到三级缓存里,表示:

"A 虽然还没完全好,但如果别人急着要,可以先拿到一个早期引用。"


第二步:给 A 注入属性时,发现它依赖 B

于是 Spring 转头去创建 B。


第三步:创建 B

同样,先实例化 B。

然后也把 B 的早期对象工厂放到三级缓存里。


第四步:给 B 注入属性时,发现它依赖 A

这时 Spring 发现 A 正在创建中,还没进一级缓存。

怎么办?

Spring 就会去 三级缓存 里找 A 对应的工厂,拿到 A 的早期引用

这个早期引用会放到二级缓存里,同时三级缓存中的那个工厂就可以删掉了。

然后 B 就可以顺利注入这个 A。


第五步:B 创建完成

B 完整初始化后,放入一级缓存


第六步:回到 A 的创建过程

这时 A 需要的 B 已经有了,于是把 B 注入给 A。

A 也完成初始化,最后放入一级缓存

这样循环依赖就解开了。


三、最本质的理解

你可以把它理解成:

  • 一级缓存:成品
  • 二级缓存:半成品对象
  • 三级缓存:半成品对象的"生产工厂"

四、要注意的一点

Spring 这种方式主要解决的是:

单例 Bean 的 setter 注入 / 字段注入 的循环依赖

但是下面这种一般解决不了:

  • 构造器注入循环依赖

因为构造器注入时,对象连 new 完都做不到,更别说提前曝光了。

例如:

  • A 的构造器里要 B
  • B 的构造器里要 A

那就谁也没法先创建出来。

相关推荐
好家伙VCC3 分钟前
**发散创新:基于Solidity的通证经济模型设计与智能合约实现**在区块链技术日益成熟的今天,**通证经济(Token Econo
java·python·区块链·智能合约
jjjava2.05 分钟前
计算机体系与进程管理全解析
java·开发语言
AI人工智能+电脑小能手7 分钟前
【大白话说Java面试题】【Java基础篇】第5题:HashMap的底层原理是什么
java·开发语言·数据结构·后端·面试·hash-index·hash
旷世奇才李先生7 分钟前
Java微服务实战:Spring Cloud Alibaba架构优化(从单体到分布式高可用)
java·微服务·架构
小成202303202657 分钟前
数据结构(整理常见结构总结到树层级)
java·c语言·数据结构·c++·链表
谢谢 啊sir9 分钟前
L1-120 智慧文本编辑器 - java
java·开发语言
weisian15113 分钟前
进阶篇-LangChain篇-15--高级Agent架构—复杂任务拆解(Plan-and-Execute架构)和多智能体协作(LangGraph)
java·架构·langchain·langgraph·planexecute架构
凤年徐15 分钟前
自动化构建工具:make 与 Makefile
android·java·linux·自动化
Xiu Yan17 分钟前
Java 转 C++ 系列:STL常用函数
java·开发语言·c++·stl·visual studio
.ZGR.20 分钟前
【全栈实战】搭建属于你的AI图像生成平台:从Java Swing 到 Web 应用
java·人工智能·node.js