Spring如何解决循环依赖?
2021-05-08 07:27
标签:ica 执行 一级缓存 access depend 运行 根据 cts public 先说一下什么是循环依赖,Spring在初始化A的时候需要注入B,而初始化B的时候需要注入A,在Spring启动后这2个Bean都要被初始化完成 Spring的循环依赖有两种场景 构造器的循环依赖,可以在构造函数中使用@Lazy注解延迟加载。在注入依赖时,先注入代理对象,当首次使用时再创建对象完成注入 属性的循环依赖主要是通过3个map来解决的 运行ConstructorMain的main方法的时候会在第一行就报异常,说明Spring没办法初始化所有的Bean,即上面这种形式的循环依赖Spring无法解决。 我们可以在ConstructorA或者ConstructorB构造函数的参数上加上@Lazy注解就可以解决 因为我们主要关注属性的循环依赖,构造器的循环依赖就不做过多分析了 先演示一下什么是属性的循环依赖 Spring容器正常启动,能获取到FieldA和FieldB这2个Bean 属性的循环依赖在面试中还是经常被问到的。总体来说也不复杂,但是涉及到Spring Bean的初始化过程,所以感觉比较复杂,我写个demo演示一下整个过程 Spring的Bean的初始化过程其实比较复杂,为了方便理解Demo,我就把Spring Bean的初始化过程分为2部分 bean初始化过程完毕,则bean就能被正常创建出来了 下面开始写Demo,ObjectFactory接口用来生产Bean,和Spring中定义的接口一样 测试一波 是不是很简单?我们只用了2个map就搞定了Spring的循环依赖 2个Map就能搞定循环依赖,那为什么Spring要用3个Map呢? 原因其实也很简单,当我们从singletonFactories中根据BeanName获取相应的ObjectFactory,然后调用getObject()这个方法返回对应的Bean。在我们的例子中 比如A依赖B和C,B和C又依赖A,如果不做缓存那么初始化B和C都会调用A对应的ObjectFactory的getObject()方法。如果做缓存只需要B或者C调用一次即可。 知道了思路,我们把上面的代码改一波,加个缓存。 我们写的getSingleton的实现和org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)的实现一模一样,这个方法几乎所有分析Spring循环依赖的文章都会提到,这次你明白工作原理是什么了把 [1]https://mp.weixin.qq.com/s/gBr3UfC1HRcw4U-ZMmtRaQ Spring如何解决循环依赖? 标签:ica 执行 一级缓存 access depend 运行 根据 cts public 原文地址:https://www.cnblogs.com/erlie/p/13179193.html介绍
构造器的循环依赖
@Component
public class ConstructorA {
private ConstructorB constructorB;
@Autowired
public ConstructorA(ConstructorB constructorB) {
this.constructorB = constructorB;
}
}
@Component
public class ConstructorB {
private ConstructorA constructorA;
@Autowired
public ConstructorB(ConstructorA constructorA) {
this.constructorA = constructorA;
}
}
@Configuration
@ComponentScan("com.javashitang.dependency.constructor")
public class ConstructorConfig {
}
public class ConstructorMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ConstructorConfig.class);
System.out.println(context.getBean(ConstructorA.class));
System.out.println(context.getBean(ConstructorB.class));
}
}
@Autowired
public ConstructorB(@Lazy ConstructorA constructorA) {
this.constructorA = constructorA;
}
属性的循环依赖
@Component
public class FieldA {
@Autowired
private FieldB fieldB;
}
@Component
public class FieldB {
@Autowired
private FieldA fieldA;
}
@Configuration
@ComponentScan("com.javashitang.dependency.field")
public class FieldConfig {
}
public class FieldMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(FieldConfig.class);
// com.javashitang.dependency.field.FieldA@3aa9e816
System.out.println(context.getBean(FieldA.class));
// com.javashitang.dependency.field.FieldB@17d99928
System.out.println(context.getBean(FieldB.class));
}
}
public interface ObjectFactory
public class DependencyDemo {
// 初始化完毕的Bean
private final Map
public static void main(String[] args) throws Exception {
DependencyDemo dependencyDemo = new DependencyDemo();
// 假装扫描出来的对象
Class[] classes = {A.class, B.class};
// 假装项目初始化所有bean
for (Class aClass : classes) {
dependencyDemo.getBean(aClass);
}
// true
System.out.println(
dependencyDemo.getBean(B.class).getA() == dependencyDemo.getBean(A.class));
// true
System.out.println(
dependencyDemo.getBean(A.class).getB() == dependencyDemo.getBean(B.class));
}
ObjectFactory的实现很简单哈,就是将实例化好的对象直接返回,但是在Spring中就没有这么简单了,执行过程比较复杂,为了避免每次拿到ObjectFactory然后调用getObject(),我们直接把ObjectFactory创建的对象缓存起来不就行了,这样就能提高效率了public class DependencyDemo {
// 初始化完毕的Bean
private final Map
总结一波
欢迎关注
参考博客
[2]https://mp.weixin.qq.com/s/5mwkgJB7GyLdKDgzijyvXw
比较详细
[1]https://zhuanlan.zhihu.com/p/84267654
[2]https://juejin.im/post/5c98a7b4f265da60ee12e9b2