Spring依赖注入(五):盘一盘Spring的三级缓存
前言
前面通过四篇文章基本上把Spring bean的依赖注入和循环依赖问题的解决盘清楚了,但是盘完回头一看,有一件事我没有说太清楚,那就是Spring的依赖注入和循环依赖的解决,使用到了Spring的一、二、三级缓存,那么问题来了,Spring的一、二、三级缓存分别是什么?Spring的一、二、三级缓存在bean的创建过程中是如何发挥作用的?自己挖的坑,说什么也得自己给补上,于是乎那就再开辟一篇,盘一盘Spring的三级缓存吧。
Spring依赖注入(四):Bean的循环依赖是如何产生和解决的?
什么是Spring的三级缓存?
1、singletonObjects:Spring的第一级缓存,用于存储完成实例化、属性注入、初始化的单例bean
2、earlySingletonObjects:Spring的第二级缓存,用于存储完成实例化,未做属性注入和初始化的的单例bean
3、singletonFactories:Spring的第三缓存,存储的是完成实例化、未完成属性注入、初始化的bean的工厂,实际就是那个用lambda表达式写的函数式接口实现,() -> getEarlyBeanReference(beanName, mbd, bean),可以提前获取到未完成创建的bean;
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/**Spring的第一级缓存,用于存储完成实例化、属性注入、初始化的单例bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Spring的第三缓存,存储的是完成实例化、未完成属性注入、初始化的bean的工厂,
实际就是那个用lambda表达式写的函数式接口实现,可以获取到bean
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Spring的第二级缓存,用于存储完成实例化,未做属性注入和初始化的的单例bean */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** 完成注册,即实例化、属性注入、初始化的单例bean都在这里 */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
/** 正在创建中的单例bean的beanName在这里面 */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
Spring的三级缓存是如何工作的?
Spring的一级缓存是如何工作的?
1、容器启动、非懒加载的单例bean注册入口:AbstractApplicationContext#refresh-->AbstractApplicationContext#finishBeanFactoryInitialization-->DefaultListableBeanFactory#preInstantiateSingletons-->AbstractBeanFactory#getBean(java.lang.String)-->AbstractBeanFactory#doGetBean
2、AbstractBeanFactory#doGetBean主要逻辑是,判断新创建的bean是否存在于Spring的一缓存中,如果在Spring一级缓存中可以获取到bean,则经过一些简单的其他逻辑过程就可以返回了;如果在Spring一级缓存中可以获取到不到bean,则调用DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory)开始创建bean;
3、DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory),参数1是beanName,参数2的类型是ObjectFactory,实际是一个lambda表达式() -> {return createBean(beanName, mbd, args);},ObjectFactory内有一个抽象方法getObject(),singletonFactory.getObject()触发执行时,触发lambda表达式中createBean(beanName, mbd, args)执行,lambda表达式的返回值即singletonFactory.getObject()返回值,lambda的表达式的逻辑就是创建一个合格的bean,即实例化、属性注入、初始化完成,可以正式使用的bean;
4、得到正式的bean后,则调用DefaultSingletonBeanRegistry#addSingleton,把bean设置到Spring一级缓存中去,并移除二级缓存、三级缓存中的内容;如果其他bean依赖当前bean,则可以直接从Spring的一级缓存中得到;
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//先从Spring的一级缓存中,尝试获取一下bean
Object singletonObject = this.singletonObjects.get(beanName);
//如果从一级缓存中获取bean为null,则开始创建bean
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
//是否属于新创建单例bean的标志位,初始值是false
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//开始调用AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])创建一个合格的bean
singletonObject = singletonFactory.getObject();
//新创建的单例bean创建成功后,设置标志位为true
newSingleton = true;
}
catch (IllegalStateException ex) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
//新创建的单例bean标志位为true时,把bean设置到Spring的一级缓存中去;
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
protected void addSingleton(String beanName, Object singletonObject) {
//操作Spring的一级缓存时,先用synchronized关键字锁定要操作的缓存资源
synchronized (this.singletonObjects) {
//把合格的bean设置到Spring一级缓存中,缓存key为beanName,value为bean本身
this.singletonObjects.put(beanName, singletonObject);
//一级缓存设置完后,移除三级缓存、二级缓存以及注册完成单例bean的缓存中的内容
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
Spring的二、三级缓存是如何工作的?
1、Spring中bean的创建主要逻辑在AbstractAutowireCapableBeanFactory#doCreateBean中,其中createBeanInstance(beanName, mbd, args)完成bean实例化,populateBean(beanName, mbd, instanceWrapper)完成bean的属性注入,在bean实例化完成后,开始属性注入前,有这么一段:DefaultSingletonBeanRegistry#addSingletonFactory被调用,即把实例化完成的bean设置到Spring的三级缓存中去,缓存key为beanName,而缓存value实际并不是一个具体的bean对象,value的类型是ObjectFactory,实际传入的是一个lambda表达式实现() -> getEarlyBeanReference(beanName, mbd, bean),ObjectFactory接口里有一个抽象方法getObject(),ObjectFactory#getObject()方法被触发的时候,会执行lambda表达式的内容; 而lambda表达式里的getEarlyBeanReference()作用就是获取提前暴露的半成品bean的引用;
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
2、DefaultSingletonBeanRegistry#addSingletonFactory内的逻辑比较简单,即把不在Spring一级缓存中的“半成品”bean,放到Spring的三级缓存(singletonFactories)中;
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
3、如果bean之间发生了循环依赖,在获取依赖bean的时候,就会尝试先从Spring的三级缓存中去获取提前暴露的“半成品”bean,以便结束循环依赖bean之间的互相等待,主要的逻辑在DefaultSingletonBeanRegistry#getSingleton(String, boolean),参数1是beanName,参数2的值为true,表示允许获取到提前暴露的“半成品”bean引用;DefaultSingletonBeanRegistry#getSingleton(String, boolean)中,调用getObject(),触发了AbstractAutowireCapableBeanFactory#getEarlyBeanReference()的调用,这里又涉及到了Spring一个特殊扩展点Springboot扩展点之SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference(),这个方法主要作用就是Spring发生循环依赖时,可以获取到提前暴露的“半成品”bean引用,而Spring内部关于SmartInstantiationAwareBeanPostProcessor有一个重要实现,即AbstractAutoProxyCreator,是AspectJAwareAdvisorAutoProxyCreator的父类,如果bean使用了aop而产生了一个代理对象,那么getObject()返回值就是bean的代理对象,并不是实际bean,而移入到二级缓存中的是“半成品”的bean的代理对象;如果没有使用到aop,那么这里就是一个普通的”半成品“bean引用,这里就是Spring二级缓存、三级缓存的妙处;
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 快速的检查一一下bean是否存在于Spring一级缓存、二级缓存
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//如果bean不存在于Spring的一级缓存、二级缓存,则锁定一级缓存
synchronized (this.singletonObjects) {
//锁定一级缓存后,再尝试获取一下
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//尝试从一级缓存中获取的结果为null,尝试从二级缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
//尝试从二级缓存中获取结果为null,则尝试从三级缓存中获取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//从三级缓存中获取结果不为空,但是三级缓存中并不是实际bean,而是一个bean工厂类
//调用getObject()触发AbstractAutowireCapableBeanFactory#getEarlyBeanReference()
singletonObject = singletonFactory.getObject();
//getEarlyBeanReference()获取提前暴露的“半成品”bean后,移入到Spring的二级缓存,并从三级缓存中移除
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
//如果bean使用了aop,则产生bean代理对象,否则还是bean本身
return wrapIfNecessary(bean, beanName, cacheKey);
}
总结
以Spring依赖注入(一):字段注入的方式是如何工作的?中示例类Student和Teacher为例,即:
1、实例化student前,判断新创建的student是否存在于Spring的一缓存中,如果在Spring一级缓存中可以获取到student,则经过一些简单的其他逻辑过程就可以返回了;如果在Spring一级缓存中可以获取到不到student,则调用DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory)开始创建student;
2、student实例化完成后,把“半成品”的student的工厂类放入Spring三级缓存中;
3、接着开始student依赖属性teacher的注入,这时发现依赖属性teacher未实例化,于是开始teacher的实例化;
4、teacher实例化前也会判断创建的teacher是否存在于Spring的一缓存中,不存于一级缓存中才开始teacher实例化;teacher实例化后,也会把“半成品”的teacher的工厂类放入Spring三级缓存中;
5、然后接着teacher对象属性注入、初始化,但是Teacher的实例化完后,开始属性注入student对象的时候,student对象还没有创建完成呢,但是Spring有三级缓存里有student的工厂类;
6、再接着getEarlyBeanReference()被触发,如果student使用了aop,那么getEarlyBeanReference()返回值就是student的代理对象,移入到二级缓存中的是“半成品”的student的代理对象;如果没有使用到aop,那么这里移入到二级缓存中的就是一个普通的”半成品“student引用;
7、teacher利用”半成品“的student完成属性注入、初始化等bean创建操作后,teacher被添加到Spring的一级缓存中,student就可以使用创建好的teacher完成依赖属性注入、初始化后,student从Spring的二级缓存中移到一级缓存中,完成student的创建,至此发生循环依赖的student、teacher互相成为了一个完成的bean。
相关文章
- spring boot自动配置原理面试题_Spring boot面试
- Spring 全家桶之 Spring Boot 2.6.4(六)- Web Develop(Part C)
- Spring学习笔记(十八)——spring日志框架的配置和使用
- Spring 全家桶之 Spring Web MVC(三)- View & ViewResolve
- 你有没有掉进去过这些Spring Boot中的“陷阱“(上)
- MyBatis-Spring整合 注入SqlSessionTemplate
- Spring Cloud 实战|整合admin模块-优化认证中心很难么?
- 9-Spring 整合 RabbitMQ
- spring boot整合shiro_Spring框架介绍及使用
- Spring boot集成海康威视门禁设备
- Spring循环依赖-spring源码详解(四)
- Spring监听器-spring源码详解(五)
- SpringBoot:模块探究之spring-boot-dependencies
- Spring事务回滚的两种方法
- 使用 Spring Cloud Bus 向所有微服务广播消息
- IntelliJ IDEA spring boot 远程Ddbug调试详解程序员
- Spring注入集合
- Spring注入内部Bean
- app微信支付宝支付后台的插件模式+回调通过spring广播处理后续业务(已亲测可用)详解编程语言
- Spring Boot(十三):spring boot小技巧详解编程语言
- Spring Boot(十二):spring boot如何测试打包部署详解编程语言
- 注入Spring精神,Redis重新发光(spirng redis)