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

浙公网安备 33010602011771号