一般想到这个问题,答案就是三级缓存,那么问题又来了,缓存的啥?用啥缓存的?为啥是三级不是二级?
三级缓存指的其实就是三个Map。源码如下图
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
用白话讲就是,创建三个map,存储对象的三个状态,对于属性依赖(也是最常见的),构造器依赖也是给你抛出错误,实在上并解决不了,为啥解决不了呢?因为一个对象想被引用,他首先得被实例化,所以,如果构造器里存在依赖那就不行了,但属性却可以后续设置, 整体流程如下图:

singletonObjects,一级缓存,存储的是所有创建好了的单例BeanearlySingletonObjects,二级缓存,完成实例化,但是还未进行属性注入及初始化的对象singletonFactories,三级缓存,提前暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象
用两级缓存行不行?行
那为什么用三级缓存?
解决代理对象的问题
为啥要解决代理对象的问题,代理对象,就是做个代理,别去访问原对象了,所以,注入的时候,你也应该注入我的代理,啥事也别找我,都找我代理
如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。
还有一点:由于我们放入缓存之后,initializeBean方法中可能存在替换bean的情况,如果只有两级缓存的话这会导致B中注入的A实例与singletonObjects中保存的AA实例不一致,而之后其他的实例注入a时,却会拿到singletonObjects中的AA实例,这样肯定是不符合预期的。
所以做个总结就是:
- 缓存的啥?各种状态的Bean
- 用啥缓存的?Map
- 为啥三级?不是二级?见上面
本文解析了Spring框架中的三级缓存机制,探讨了为何采用三级而非二级,并重点讲解了如何通过三级缓存处理代理对象,避免AOP过早代理带来的问题。
542

被折叠的 条评论
为什么被折叠?



