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,代理,bean,创建,三级 来源: https://www.cnblogs.com/banzhuandang/p/16192621.html