快速导航
一、Spring的三级缓存是什么?
三级缓存
简单来说,就是map,和我们在开发中new的map没有任何区别。
/** Cache of singleton objects: bean name to bean instance. */
// 一级缓存:存储完整的单例对象。key是对象名称,value是对象实例。
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
// 三级缓存:存储生成单例对象的工厂对象。key是对象名称,value是工厂实例。
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
// 二级缓存:存储实例化后的对象(对象未注入属性和初始化)。key是对象名称,value是对象实例。
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
从上面的代码中可以看出,三级缓存就是3个全局的Map。
只是一级缓存和二级缓存使用的是线程安全的容器 ConcurrentHashMap
保存。
这里提两个问题,大家可以思考一下:
1.这里的三个容器变量名为什么都带着singleton?
2.为什么一级缓存和二级缓存使用的ConcurrentHashMap,而三级缓存使用HashMap?
容器只是个工具,怎么用才是我们需要了解的关键,什么时候给容器里存入Bean,把Bean存入哪个容器,什么时候清空容器,这就不得不了解一下Spring中Bean的生命周期了。
SpringBean 的生命周期:
BeanFactory关于Bean初始化注释:
- BeanNameAware’s setBeanName 设置实例名称
- BeanClassLoaderAware’s setBeanClassLoader 设置实例类加载器
- BeanFactoryAware’s setBeanFactory 设置Bean工厂
- EnvironmentAware’s setEnvironment 设置环境
- EmbeddedValueResolverAware’s setEmbeddedValueResolver 设置内嵌的值解析器
- ResourceLoaderAware’s setResourceLoader (only applicable when running in an application context)
- ApplicationEventPublisherAware’s setApplicationEventPublisher (only applicable when running in an application context)
- MessageSourceAware’s setMessageSource (only applicable when running in an application context)
- ApplicationContextAware’s setApplicationContext (only applicable when running in an application context)
- ServletContextAware’s setServletContext (only applicable when running in a web application context)
- postProcessBeforeInitialization methods of BeanPostProcessors
- InitializingBean’s afterPropertiesSet
- a custom init-method definition
- postProcessAfterInitialization methods of BeanPostProcessors
On shutdown of a bean factory, the following lifecycle methods apply:
- postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
- DisposableBean’s destroy
- a custom destroy-method definition
分析:
Bean的创建过程:
- 前面10个都是 xxxAware.setXXX()方法
- 然后就是
BeanPostProcessors.postProcessBeforeInitialization()
InitializingBean.afterPropertiesSet()
- 自定义的
init()
方法 BeanPostProcessors.postProcessAfterInitialization()
Bean的销毁过程:
DestructionAwareBeanPostProcessors.postProcessBeforeDestruction()
DisposableBean.destroy()
- 自定义的
destroy()
方法
Spring Bean创建的核心逻辑:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
createBeanInstance()
实例化Bean
populateBean()
填充属性和initializeBean()
初始化
- 进入initializeBean()
invokeAwareMethods()
源码
applyBeanPostProcessorsBeforeInitialization()
invokeInitMethods()
7.applyBeanPostProcessorsAfterInitialization()
二、Spring的三级缓存解决了什么问题?
1.循环依赖问题
设想一下没有三级缓存的循环依赖问题:ServiceA依赖ServiceB,ServiceB依赖ServiceA
- ServiceA实例化,然后在属性填充的时候,发现依赖ServiceB。在Spring容器中找ServiceB,没有找到。
- ServiceA暂停属性注入,开始实例化ServiceB,然后在属性填充的时候,发现依赖ServiceA,于是又在Spring容器中找ServiceA,同样没有找到。
- GG了。
加入了三级缓存:
- ServiceA实例化,之后将实例化的不完整的实例ServiceA放入三级缓存。然后在属性填充的时候,发现ServiceA依赖ServiceB。在Spring容器中的一级缓存、二级缓存和三级缓存中找ServiceB,没有找到。
- ServiceA暂停属性注入,开始实例化ServiceB,同样将不完整的ServixcB实例放入三级缓存。然后在属性填充的时候,发现依赖ServiceA,于是又在Spring容器中找ServiceA,先找了一级缓存和二级缓存,没找到。在三级缓存中找到了不完整的实例ServiceA,然后将ServiceB从三级缓冲中移除,放入二级缓存,然后成功的对ServiceB进行了属性填充和初始化操作,然后从二级缓存移除,放入一级缓存。
- ServiceA继续属性注入,依次放入二级缓存和一级缓存。
问题:
解决循环依赖的问题有两级缓存就够了,为什么要用三级缓存呢?
答:因为Spring需要支持AOP
2.支持Spring的AOP
在Bean被AOP进行了切面代理之后,三级缓存中的singletonFactory
获取到的对象实例是目标Bean的一个代理对象。
每次获取到的都是新的代理对象,就破坏了Spring解决循环依赖问题的基础,即所有的对象都是单例的。
而加入了二级缓存以后,代理对象也是只获取一次,然后放入二级缓存备用。
参考资料:
https://topjavaer.cn/advance/excellent-article/6-spring-three-cache.html#%E4%B8%89%E7%BA%A7%E7%BC%93%E5%AD%98%E8%A7%A3%E5%86%B3%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96
https://www.mianshiya.com/bank/1790683494127804418/question/1780933295387734017
标签:缓存,白话,Spring,ServiceA,Bean,实例,三级 From: https://blog.csdn.net/qq_22129643/article/details/142137210