Spring使用三级缓存原因总结

这个和动态代理相关,当然前提是在循环依赖的情况;一般情况下,不存在循环依赖的情况,在Spring创建bean完整后才会进行动态代理,即完成bean的初始化才会进行动态代理,这是Spring的设计原则。

 

在Spring实例化后有这一条语句 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
这个lambda表达式是创建动态代理对象的,具体什么时候执行要看什么时候调用内部类接口,其次是将addSingletonFactory方法将beanName对应的对象引用放到三级缓存中。

当存在循环依赖并且是代理对象时,实例化后填充属性,发现是循环依赖,假设A和B是循环依赖,且是代理对象。A实例化后填充属性发现依赖B需要获取B的bean对象,在获取时走的是getBean方法,它首先从缓存获取,B的bean也是第一次创建所以缓存中不存在,这时就去创建B的bean对象,B的bean对象进行实例化,并将beanName对应的对象引用放入三级缓存。同样走到了填充属性,发现B依赖A,于是使用getBean方法获取A的bean对象,首先查询缓存,我们知道这时A和B的的对象引用在三级缓存中是可以查询到的,当查询到对象引用就去调用 getObject方法对应的实现,就是上面的匿名内部类的getEarlyBeanReference方法,这个方法作用就是如果是代理对象就创建代理对象,如果不是直接返回bean。拿到A实例对应的代理对象后将代理对象从三级缓存移到二级缓存,B这时也完成了属性填充。紧接着就初始化,初始化完成后,将代理对象从缓存中移除,直接放到单例池即一级缓存中。这时A填充属性直接从单例池中拿到B,A初始化完毕。在这个过程中,如果还有其他的对象依赖A代理,直接从二级缓存获取即可。

 

如果不使用三级缓存而只使用二级缓存行不行?

     存在需要代理的对象时,实例化后判断是否需要代理,如果需要代理直接创建代理对象,将代理对象放到二级缓存中,同样举例A和B,将A的代理对象放到二级缓存中,实例化B时,获取A的代理对象然后完成B的属性填充和初始化。然后将B的代理对象从二级缓存删除,初始化好的B放到单例池中,A直接从单例池拿到B的代理对象,完成属性填充。这样做似乎也可以,但是存在一点,一般的代理对象是在初始化后完成的动态代理,而只使用二级缓存只能在实例化后就要进行动态代理了,不符合Spring的设计原则以及影响Spring的生命周期。一般的代理对象的初始化并不需要三级缓存初始化完成后直接创建代理对象即可。

 

如果只用一级缓存?

还有一点就是如果A,B,C都是需要进行动态代理,A依赖B,C,B依赖A,C依赖A。假设A进行实例化,进行属性填充,依赖B和C,然后B进行实例化填充属性,从缓存获取A代理,获取A后B完成属性填充,完成初始化然后从缓存中删除B代理。同样C实例化依赖A,同样获取A的代理对象,使用二级缓存时,再次获取A的代理对象,A的代理对象对于B和C而言是不同的;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值