Spring--循环依赖的原理(四)--为什么用三级缓存,而不是二级

原文网址:Spring--循环依赖的原理(四)--为什么用三级缓存,而不是二级_IT利刃出鞘的博客-CSDN博客

简介

说明

        本文介绍Spring(SpringBoot)为什么使用三级缓存来解决循环依赖(为什么不使用二级)。

问题引出

在上边的分析中我们可以提出两个问题:

  1. 二级缓存好像没有用到?那么它什么时候会用到?
  2. 为什么第三级缓存要用一个工厂,删除第三级缓存,只用第一二级不可以吗?

 文章系列

  1. Spring--循环依赖的原理(一)--什么是循环依赖_IT利刃出鞘的博客-CSDN博客
  2. Spring--循环依赖的原理(二)--打断点分析_IT利刃出鞘的博客-CSDN博客
  3. Spring--循环依赖的原理(三)--原理概述_IT利刃出鞘的博客-CSDN博客
  4. Spring--循环依赖的原理(四)--为什么用三级缓存,而不是二级_IT利刃出鞘的博客-CSDN博客

可以去掉第二级缓存吗?

简介

不可以去掉第二级缓存。

详解

假如有这种情况:a实例同时依赖于b和c,b和c都依赖于a。

        a实例化时,先提前暴露objectFactorya到三级缓存,调用getBean(b)依赖注入b实例。b实例化之后,提前暴露objectFactoryb到三级缓存,调用getBean(a)依赖注入a实例,由于提前暴露了objectFactorya,此时可以从三级缓存中获取到a实例, b实例完成了依赖注入,升级为一级缓存。a实例化再getBean(c)依赖注入c实例,c实例化之后,提前暴露objectFactoryc到三级缓存,调用getBean(a)依赖注入a实例,由于提前暴露了objectFactorya,此时可以从三级缓存中获取到a实例。注意这里又要从三级缓存中获取a实例,我们知道三级缓存中的实例是通过调用singletonFactory.getObject()方法获取的,返回结果每次都可能不一样。如果不用二级缓存,这里会有问题,两次获取的a实例不一样。

可以去掉第三级缓存吗?

概述

结论

不可以去掉第三级缓存。

原因

Spring 的设计原则是在 IOC 结束之后再AOP( bean 实例化、属性设置、初始化之后再通过进行AOP(生成代理对象))。即:AOP的实现需要与bean的生命周期的创建分离。

  1. 为了解决循环依赖但又尽量不打破这个设计原则的情况下,使用了第三级缓存(key:bean名字,value:ObjectFactory)。
    1. 前边分析过,它是将一个函数式接口作为ObjectFactory,相当于延迟初始化。AOP中发生循环依赖时,通过调用Object的getObject()方法获取到三级缓存中的对象。
  2. 如果去掉第三级缓存,将AOP的代理工作放到第二级缓存,这样的话,bean在创建过程中就先生成代理对象再初始化和其他工作,与Spring的AOP的设计原则相违背。

详解

        上边:“bean何时被加入第3级缓存?”  我们可以得到,第三级缓存里存放的value是:AbstractAutowireCapableBeanFactory#getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean)。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}

可以看到实际调用SmartInstantiationAwareBeanPostProcessor接口的getEarlyBeanReference(Object bean, String beanName)方法,此接口有以下实现类:

InstantiationAwareBeanPostProcessorAdapter

@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
	return bean;
}

直接返回bean,这里看起来第三级缓存没必要存在。但是,看另一个实现类:

AbstractAutoProxyCreator

@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
	Object cacheKey = getCacheKey(bean.getClass(), beanName);
	this.earlyProxyReferences.put(cacheKey, bean);
	return wrapIfNecessary(bean, beanName, cacheKey);
}

这里把对象放入第二级缓存。

Spring(SpringBoot)--AOP的原理_IT利刃出鞘的博客-CSDN博客 曾分析过AOP:将横切逻辑织入目标Bean:AbstractAutoProxyCreator#postProcessAfterInitialization方法,在Bean实例化之后被调用。

来看postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

把key对应的项从二级缓存中移除,如果原来二级缓存中就是这个bean,则返回此bean,否则,返回代理类。

猜你喜欢

转载自blog.csdn.net/feiying0canglang/article/details/125332773
今日推荐