spring 三级缓存机制的作用(spring如何解决循环依赖)


spring getBean三级缓存机制的作用
一级缓存:是单例池,所有初始化完成后的单例对象都会存到这里
二级缓存:存放没有完全被spring初始化完的bean
三级缓存:为了解决循环依赖

场景为:
classA依赖classB,classB也依赖classA
这种情况下,在创建A的时候因为B还没有被创建,因此无法完成创建,而B又依赖于A,因此B也无法完成创建
这样就形成了死锁。spring利用了三级缓存机制解决了这个问题。
spring中,bean的初始化只是其生命周期的一部分(第一步),在bean初始化之后,spring会生成一个ObjectFactory<?>(这是一个函数式接口)存到三级缓存,它的作用是生产一个bean(getObject方法),所有的bean在初始化未完成(对于spring的bean生命周期来说)的时候都会先存一个ObjectFactory<?>到三级缓存。

当A被创建的时候,因为依赖于B这个时候spring会调用getBean("B")(递归操作)去获取B,因为B没有被加载,所以spring又会去加载B,当B被实例化后设置B的属性,因为B又是依赖于A的,这个时候spring会先从单例池中取A发现没有,又从二级缓存取,发现还没有,最后去三级缓存中取得ObjectFactory(前面说到所有的bean在初始化未完成的时候都会先存入到三级缓存),执行ObjectFactory.getObject()这个方法会调用getEarlyBeanReference方法(函数式接口),这个方法会返回一个bean实例。然后B取得了A完成创建,返回给A,A也得到了B,循环依赖问题被解决。

到这里我有个疑惑,为什么不直接在二级缓存中存bean的实例呢?为什么要使用ObjectFactory函数式接口呢?

查看源码后发现,getEarlyBeanReference这个方法会判断传入的这个类有没有被AOP增强,如果被AOP增强了,则返回一个被AOP包装过后的实例(在被AOP增强的时候,返回的是一个代理类(这个时候会重新创建一个实例(createProxy方法)))。


如果直接在二级缓存中存入bean实例(此时没有被AOP增强),然后去设置了属性B(B这个时候会去三级缓存中找A(A这个时候没有被AOP增强)),B属性设置完成后,A最后会去被AOP增强(这个时候A会重新创建)然后放入到单例池,这个时候B中的A对象就跟单例池里的A对象不是一个对象了。

这个时候又有一个疑问,既然要提前被AOP包装,为什么不直接把AOP包装后的类放入到二级缓存呢?而要使用三级缓存呢?
这里应该跟spring的设计思想有关,spring想尽可能的按照常规的bean的生命周期来创建bean,除非要解决循环依赖,不然三级缓存的ObjectFactory永远都用不到(二级缓存也用不到)。最后在实例被加入到一级缓存的时候,会把二级缓存和三级缓存中的实例移除。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM