spring如何解决循环依赖的问题
spring如何解决循环依赖的问题
@Service
public class A {
@Autowired
private B b;
}
@Service
public class B {
@Autowired
private A a;
}
A,B 两个类相互依赖,但启动并不报错,Spring 通过 Java 的引用传递,以及提前暴露对象到三级缓存中和延后设置 field 属性解决此问题
Spring 解决循环依赖的过程
- 首先查一二级缓存中是否存有 A
- 若没有A,spring调用三级缓存中的A对象创建工厂创建A,此时的A并没有完成属性注入(不完整的Bean)并将创建出来的 A放到 Spring 的二级缓存中;
- 因为 A的 b 属性需填充,spring到一级二级缓存中查询 B 对象,没查到,触发 B 的创建流程;
- spring调用三级缓存中的B对象创建工厂创建B,并将创建出来的 B 对象放到 Spring 的二级缓存中(这个时刻,二级缓存有A,B,一级缓存啥都没有)
- B 的 a 属性为空,把二级缓存中的 a填充,此时B完整了!迁入一级缓存;
- 填充A 的 b 属性,依次查一级二级缓存,一级缓存中拿到 B,完成属性注入,此时A完整了!迁入一级缓存,循环依赖到此解决。
Spring三级缓存
- singletonObjects:一级缓存,存放完整的 bean,从该缓存中取出的 bean 可直接用
- earlySingletonObjects:二级缓存,存放不完整的bean,未完成属性注入和执行 init 方法,用于解决循环依赖
- singletonFactories:三级缓存,存储能够产生bean的ObjectFactory,不直接存储bean的实例
解决构造器注入引发的循环依赖问题
⚠️下述代码运行报错
@Service
public class A {
private B b;
@Autowired
public A(B b){ this.b = b; }
}
@Service
public class B {
private A a;
@Autowired
public B(A a){ this.a = a; }
}
如何解决?先说解决方案
-
通过 @Scope 的 proxyMode 属性来设置类的代理模式
@Service public class A { private B b; @Autowired public A(B b){ this.b = b; } } // 使用CGLIB和JDK代理均可,不过JDK麻烦点 @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) @Service public class B { private A a; @Autowired public B(A a){ this.a = a; } }
ScopedProxyMode枚举
DEFAULT
不使用代理NO
不使用代理INTERFACES
使用JDK动态代理TARGET_CLASS
使用 CGLIB 动态代理
-
使用 @Lazy 注解
@Service public class A { private B b; @Autowired public A(B b){ this.b = b; } } @Service public class B { private A a; @Autowired public B(@Lazy A a){ this.a = a; } }
再阐述原理
这两种方式都是通过动态代理来避免了循环依赖,但与属性注入不同!AB相互依赖,创建A时需要B,而B 是可延迟加载或使用代理模式。那么此时spring创建一个 B 类的代理类 Bproxy,A使用Bproxy完成B属性注入,A完整了,迁入一级缓存,B则直接在一级缓存中找A完成A属性注入。
这里有一个点很重要——A并不是直接依赖B,而是B的代理Bproxy
⚠️ 暂忙!源码解析空时写
本文来自博客园,作者:勤匠,转载请注明原文链接:https://www.cnblogs.com/JarryShu/articles/18315562
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现