Java教程

spring为何要用三级缓存解决循环依赖问题

本文主要是介绍spring为何要用三级缓存解决循环依赖问题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1、什么是循环依赖

  在spring对bean的管理中,如何出现如下两个类:A类中有属性B,B类中中属性A;在单例模式下就会产生循环依赖问题,为什么会产生循环依赖问题,与spring的设计有关,跟bean的创建流程息息相关。

  

2、简单描述bean的创建过程

  下图是bean创建的一个大体流程,先实例化bean—>填充bean里的属性—>执行beanPostProcessor接口中before方法—>初始化(执行配置的initMethod方法)—>执行beanPostProcessor接口中after方法

  通过这样的一个流程才得到一个完整的bean对象

                            

3、spring解决AB两个类循环依赖的流程

    spring中bean的三级缓存

  

  1)、先创建A对象,先放入到三级缓存中,再执行填充属性方法,这时候发现需要填充B对象,而B对象还没有开始创建,那么就先去创建B对象

  

    此时三个缓存中存放的内容如下

    

  2)、执行完第一步后,这时候需要创建B对象,实例化B之后,先把B对象放入的三级缓存,再填充A属性,此时三个缓存中存放的内容如下

  

  3)、填充B类的属性时,又需要创建A对象(如此反复,产生循环引用问题),spring是怎么做的呢

  B对象中需要填充A属性,需要去创建A对象,在创建前先去缓存中找一找看是否存在

  先从一级缓存中找,如何不存在,则判断该对象是否正在创建中,显然A对象确实正在创建中;再从二级缓存中找,如果没有,那么再从三级缓存中找

  找到之后,执行getEarlyBeanReference()返回一个早期bean对象,并放入二级缓存,同时删除三级缓存

  

  此时三个缓存中存放的内容如下(红色表示删除)

   

   4)、拿到A对象之后就可以对B对象中的A属性进行赋值操作,此时B就是一个完整的对象,此时三个缓存中存放的内容如下(红色表示删除)

    B对象初始化完成之后,把B对象放入一级缓存,再删除二级缓存和三级缓存

    

        

  5)、再回到A对象填充属性方法,此时B对象也创建完成,可以填充A对象的b属性,填充完成之后,再执行后续步骤完成A对象的初始化,在放入一级缓存,同时删除二级和三级缓存

  

4、为什么spring要用三级缓存来解决循环依赖?

  如果我们能保证所有的bean对象都不会被aop代理,那么二级缓存就能解决循环依赖问题,但是在spring中很多的bean都需要被代理。

  spring的设计原则是在bean初始化完成才会创建代理对象,如果按照设计,那么就会出现一个问题:注入的对象和最终暴露的对象不是同一个对象,违背了单例的原则,所以需要将代理操作提前

  使用二级缓存,可以满足解决循环依赖的问题,那么就意味着所以bean的创建代理的操作都要提前到实例化后初始化之前去创建代理对象,再将代理对象放入到二级缓存中,这次的操作是与设计相悖的;

  那么何不在需要的时候再去创建代理对象呢,不需要的时候仍然在初始化后再创建代理对象呢,所以这个时候就引入了三级缓存,在三级缓存中放入ObjectFactory<?>,等需要的时候再去调用ObejctFactory.getObeject方法,该方法只会执行一次,就直接删除三级缓存保证了单例需求

  

如果不需要代理直接返回普通对象,如果需要代理就返回代理对象
这样做的好处是:
  1)延迟代理,只要不发生循环依赖,就不会创建提前创建代理
    有循环依赖时代理创建可以看下图,是在bena初始化完成之前创建代理的

 

    没有循环依赖时,下图是在初始化完成之后执行后置处理器时创建代理对象的

 

 

  2)、发生了循环依赖,也只会生产一次代理对象的创建,满足单例

 


 

 

   

这篇关于spring为何要用三级缓存解决循环依赖问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!