spring 三级缓存解决循环依赖

循环依赖:就是N个类循环(嵌套)引用。
通俗的讲就是N个Bean互相引用对方,最终形成闭环。用一副经典的图示可以表示成这样(A、B、C都代表对象,虚线代表引用关系):


三大循环依赖场景

构造器注入依赖

@Service
public class A {
    public A(B b) {
    }
}
@Service
public class B {
    public B(A a) {
    }
}

结果:项目启动失败抛出异常BeanCurrentlyInCreationException

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:339)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:215)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)

构造器注入构成的循环依赖,此种循环依赖方式是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖。这也是构造器注入的最大劣势(它有很多独特的优势,请小伙伴自行发掘)

根本原因:Spring解决循环依赖依靠的是Bean的“中间态”这个概念,而这个中间态指的是已经实例化,但还没初始化的状态。而构造器是完成实例化的东东,所以构造器的循环依赖无法解决~~

field属性注入(setter方法注入)循环依赖

@Service
public class A {
    @Autowired
    private B b;
}

@Service
public class B {
    @Autowired
    private A a;
}

这种可以启动成功,正常使用。

prototype field属性注入循环依赖

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class A {
    @Autowired
    private B b;
}

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class B {
    @Autowired
    private A a;
}

结果:需要注意的是本例中启动时是不会报错的(因为非单例Bean默认不会初始化,而是使用时才会初始化),所以很简单咱们只需要手动getBean()或者在一个单例Bean内@Autowired一下它即可.
这样启动就报错了。

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mytest.TestSpringBean': Unsatisfied dependency expressed through field 'a'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'a': Unsatisfied dependency expressed through field 'b'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'b': Unsatisfied dependency expressed through field 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?

    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)

对于Spring循环依赖的情况总结如下:

不能解决的情况:

  1. 构造器注入循环依赖
  2. prototype field属性注入循环依赖
    能解决的情况:
  3. field属性注入(setter方法注入)循环依赖

上面内容列的不详细。具体查看参考链接。

小结:

  • 使用context.getBean(A.class),旨在获取容器内的单例A(若A不存在,就会走A这个Bean的创建流程),显然初次获取A是不存在的,因此走A的创建之路~
  • 实例化A(注意此处仅仅是实例化),并将它放进缓存(此时A已经实例化完成,已经可以被引用了)
  • 初始化A:@Autowired依赖注入B(此时需要去容器内获取B)
  • 为了完成依赖注入B,会通过getBean(B)去容器内找B。但此时B在容器内不存在,就走向B的创建之路~
  • 实例化B,并将其放入缓存。(此时B也能够被引用了)
  • 初始化B,@Autowired依赖注入A(此时需要去容器内获取A)
  • 此处重要:初始化B时会调用getBean(A)去容器内找到A,上面我们已经说过了此时候因为A已经实例化完成了并且放进了缓存里,所以这个时候去看缓存里是已经存在A的引用了的,所以getBean(A)能够正常返回
  • B初始化成功(此时已经注入A成功了,已成功持有A的引用了),return(注意此处return相当于是返回最上面的getBean(B)这句代码,回到了初始化A的流程中~)。
  • 因为B实例已经成功返回了,因此最终A也初始化成功
  • 到此,B持有的已经是初始化完成的A,A持有的也是初始化完成的B,完美~

参考链接:
https://cloud.tencent.com/developer/article/1497692

你可能感兴趣的:(spring 三级缓存解决循环依赖)