欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring解决Bean的循环依赖

程序员文章站 2022-05-22 19:54:16
...

什么是循环依赖

也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。

循环依赖类型

spring Bean 的循环依赖解决主要是根据三级缓存来实现的。

  • 一种是构造器的相互依赖(没法解决的原因是三级缓存的前提是已经执行了构造器。)
  • 另外一种是field属性的循环依赖

属性的相互依赖

  • 属性的相互依赖就是A类的属性中有B,B类的属性中有A,如下:
  • 这里仅仅是两个类的循环依赖,当然还有更多的类相互依赖
public class A{
    private B b;
}
​
public class B{
    private A a;
}

构造器的依赖

  • 构造器的依赖就是A类的构造器需要传入B类对象,B的构造器需要传入A类对象,如下:
public class A{
    public A(B b){}
}
​
public class B{
    private B(A a){}
}

如何解决

Spring只能解决属性的循环依赖,构造器的循环依赖是不能解决的。
spring中解决循环依赖的核心思想就是利用三级缓存,先创建Bean,后为各个属性赋值具体什么是三级缓存呢?

三级缓存

三级缓存的实现在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry类中,如下:

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
单例对象缓存池,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象

private final Map<String, Object> earlySingletonObjects = newHashMap<>(16);
早期的单例对象也叫提前暴露的单例对象,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象。

private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
单例工厂的缓存,beanName->ObjectFactory

为什么不能解决构造器的循环依赖

Spring解决循环依赖主要是依赖三级缓存,但是的在调用构造方法之前还未将其放入三级缓存之中,因此后续的依赖调用构造方法的时候并不能从三级缓存中获取到依赖的Bean,因此不能解决。

Spring为什么不能解决多例(@SCOP=“prototype”)的循环依赖

多实例Bean是每次调用一次getBean都会执行一次构造方法并且未属性赋值,根本没有三级缓存,因此解决循环依赖。

相关标签: spring 面试