一、Spring 三级缓存
1、三级缓存的定义
看源码的DefaultSingletonBeanRegistry中有三个Map对象,通常情况下,称singletonObjects为一级缓存,earlySingletonObjects为二级缓存,singletonFactories 为三级缓存。
等级 名称 说明 一级 singletonObjects 可以理解为单例池 二级 earlySingletonObjects 早期单例对象缓存 三级 singletonFactories 单例工厂缓存 public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { /** Cache of singleton objects: bean name to bean instance. */ //一级缓存:单例对象缓存池,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ //三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例还未具备属性 // 用于保存beanName和创建bean的工厂之间的关系map,单例Bean在创建之初过早的暴露出去的Factory, // 为什么采用工厂方式,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ //二级缓存:早期的单例对象,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象 // 执行了工厂方法生产出来的Bean,bean被放进去之后, // 那么当bean在创建过程中,就可以通过getBean方法获取到 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);、 /** Names of beans that are currently in creation. */ //三级缓存是用来解决循环依赖,而这个缓存就是用来检测是否存在循环依赖的 private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); }2、三级缓存的作用
名称 作用 singletonObjects 存放初始化后的单例对象,也就是完成的bean对象 earlySingletonObjects 存放实例化,未完成初始化的单例对象(未完成属性注入的对象),也是用来解决性能问题 singletonFactories 存放ObjectFactory对象,存放的是工厂对象,主要用来解决循环依赖和aop的问题3、为什么需要第三级缓存?
实际上使用二级缓存就能够实现循环依赖的解决,将二级缓存用来存放早期单例对象(半成品),然后一样的走生命周期的流程,也没有问题,为什么还需要三级缓存?
这个问题反映了spring设计的相当的精妙,如果说,注入的对象实现了aop功能,那么通过循环依赖注入其他bean的时候,bean是原始对象,也就是说没有经过aop的处理,不是最终的代理对象,需要通过三级缓存的ObjectFactory对象工厂才能解决aop的问题,才能获得最终需要的代理对象。
二、循环依赖是如何解决的
假设情景A依赖于B,B依赖于A
首先A通过getBean调到doCreateBean(Spring通过getBean方法获取bean),初步实例化即调用createBeanInstance()方法后,属性注入之前进入到下边代码中
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { //省略前面的部分代码 // even when triggered by lifecycle interfaces like BeanFactoryAware. // 7.判断是否需要提早曝光实例:单例 && 允许循环依赖 && 当前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"); } // 8.提前曝光beanName的ObjectFactory,用于解决循环引用 // 8.1 应用后置处理器SmartInstantiationAwareBeanPostProcessor,允许返回指定bean的早期引用,若没有则直接返回bean addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. // 初始化bean实例。 Object exposedObject = bean; try { // 9.对bean进行属性填充;其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean实例 populateBean(beanName, mbd, instanceWrapper); // 10.对bean进行初始化 //初始化bean,过程如下: //1:判断是否实现了BeanNameAware,BeanClassLoaderAware, // BeanFactoryAware方法,如果有,则设置相关的属性 //2: 调用bean初始化的前置(BeanPostProcessor)操作 //3: 执行初始化的方法。 // 如果有initializingBean,则调用afterPropertiesSet // 如果有InitMethod,则调用初始方法 //4: 调用bean初始化的后置(BeanPostProcessor)操作 exposedObject = initializeBean(beanName, exposedObject, mbd); } //省略中间的部分代码 // 13.完成创建并返回 return exposedObject; } }属性注入之前Spring将Bean包装成一个工厂添加进了三级缓存中,即调用addSingletonFactory()方法
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { // 这里传入的参数也是一个lambda表达式,() -> getEarlyBeanReference(beanName, mbd, bean) protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { // 1.如果beanName不存在于singletonObjects缓存中 if (!this.singletonObjects.containsKey(beanName)) { //往三级缓存里添加 // 2.将beanName和singletonFactory注册到singletonFactories缓存(beanName -> 该beanName的单例工厂) this.singletonFactories.put(beanName, singletonFactory); //清除此Bean在二级缓存里的缓存信息 // 3.移除earlySingletonObjects缓存中的beanName(beanName -> beanName的早期单例对象) this.earlySingletonObjects.remove(beanName); //这里为了记录注册单例的顺序 // 4.将beanName注册到registeredSingletons缓存(已经注册的单例集合) this.registeredSingletons.add(beanName); } } } }这里只是添加了一个工厂(通过这个工厂(ObjectFactory)的getObject方法可以得到一个对象),执行工厂的getObject相当于执行getEarlyBeanReference。那么,什么时候会去调用这个工厂的getObject方法呢?
当A开始属性注入,B开始实例化时,同样会通过getBean,同样会跟A一样属性注入,再次实例化A,此时再次实例化A时,getBean经过getSingleton会从三级缓存中拿出ObjectFactory,调用getObject会拿到A的对象。
到此为止,循环依赖被解决。
解决循环依赖后,会在doCreateBean()方法中调用populateBean()方法填充属性,完成对bean的依赖属性进行注入(@Autowired)。
即在AbstractBeanFactory类中:
-
通过 getBean(String name)方法、调用doGetBean()方法、在doGetBean()方法内部调用Object sharedInstance = getSingleton(beanName);代码,在getSingleton()方法中会从三级缓存中拿出ObjectFactory
-
通过ObjectFactory单例对象工厂创建的单例对象,放到早期单例对象缓存中即二级缓存earlySingletonObjects,并在三级缓存中移除beanName对应的单例对象工厂
循环依赖确实被解决了,但是从过程看,似乎ObjectFactory缓存没什么存在的必要?似乎singletonObjects和earlySingletonObjects已经可以解决依赖问题了?
那么三级缓存到底有什么作用呢?我们再仔细分析下singletonFactories
在doCreateBean()方法调用addSingletonFactory()方法,提前曝光beanName的ObjectFactory,用于解决循环引用的时候,会调用getEarlyBeanReference()方法,即addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));方法的时候
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; // 1.如果bean不为空 && mbd不是合成 && 存在InstantiationAwareBeanPostProcessors if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { // 2.应用所有SmartInstantiationAwareBeanPostProcessor,调用getEarlyBeanReference方法 if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; // 3.允许SmartInstantiationAwareBeanPostProcessor返回指定bean的早期引用 exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } // 4.返回要作为bean引用公开的对象,如果没有SmartInstantiationAwareBeanPostProcessor修改,则返回的是入参的bean对象本身 return exposedObject; } }它实际上就是调用了后置处理器的getEarlyBeanReference,而真正实现了这个方法的后置处理器只有一个,就是通过@EnableAspectJAutoProxy注解导入的AnnotationAwareAspectJAutoProxyCreator。也就是说如果在不考虑AOP的情况下,上面的代码等价于:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; return exposedObject; } }也就是说这个工厂啥都没干,直接将实例化阶段创建的对象返回了!所以说在不考虑AOP的情况下三级缓存有用嘛?讲道理,真的没什么用。
结合了AOP的循环依赖
上面已经说过了,在普通的循环依赖的情况下,使用二级缓存也能解决循环依赖,那么三级缓存就显得可有可无了。其实、三级缓存实际上跟Spring中的AOP相关,我们再来看一看getEarlyBeanReference的代码:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; // 1.如果bean不为空 && mbd不是合成 && 存在InstantiationAwareBeanPostProcessors if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { // 2.应用所有SmartInstantiationAwareBeanPostProcessor,调用getEarlyBeanReference方法 if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; // 3.允许SmartInstantiationAwareBeanPostProcessor返回指定bean的早期引用 exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } // 4.返回要作为bean引用公开的对象,如果没有SmartInstantiationAwareBeanPostProcessor修改,则返回的是入参的bean对象本身 return exposedObject; } }如果在开启AOP的情况下,那么就是调用到AnnotationAwareAspectJAutoProxyCreator的父类的AbstractAutoProxyCreator的getEarlyBeanReference方法,对应的源码如下:
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { @Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); this.earlyProxyReferences.put(cacheKey, bean); // 如果需要代理,返回一个代理对象,不需要代理,直接返回当前传入的这个bean对象 return wrapIfNecessary(bean, beanName, cacheKey); } }wrapIfNecessary为Spring实现Bean代理的核心方法
- wrapIfNecessary在两处会被调用,一处是getEarlyBeanReference,另一处是postProcessAfterInitialization
- 在wrapIfNecessary方法内部调用getAdvicesAndAdvisorsForBean()返回匹配当前Bean的所有Advice\Advisor\Interceptor,用于判断此该类是否需要创建代理。
回到上面的例子,我们对A进行了AOP代理的话,那么此时getEarlyBeanReference将返回一个代理后的对象,而不是实例化阶段创建的对象,这样就意味着B中注入的A将是一个代理对象而不是A的实例化阶段创建后的对象。
三级缓存的意义何在?
就以我们上的A、B为例,其中A被AOP代理,我们先分析下使用了三级缓存的情况下,A、B的创建流程
假设不使用三级缓存,直接用二级缓存中,也是可以实现的,那么三级缓存搭配二级缓存的存在有什么意义呢?
上面两个流程的唯一区别在于为A对象创建代理的时机不同,在使用了三级缓存的情况下为A创建代理的时机是在B中需要注入A的时候,而不使用三级缓存的话在A实例化后就需要马上为A创建代理然后放入到二级缓存中去。对于整个A、B的创建过程而言,消耗的时间是一样的(所以常见的三级缓存提高了效率这种说法都是错误的)
上述这种情况下,差别就是在哪里创建代理。如果不用三级缓存,使用二级缓存,违背了Spring在结合AOP跟Bean的生命周期的设计!Spring结合AOP跟Bean的生命周期本身就是通过AbstractAutoProxyCreator这个后置处理器来完成的,在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖,那没有办法,只有给Bean先创建代理,但是没有出现循环依赖的情况下,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。
Spring Bean的生命周期:https://blog.51cto.com/u_14014612/5995566
参考: https://blog.csdn.net/qq_38762237/article/details/108468333
https://juejin.cn/post/6930904292958142478#heading-5
https://www.cnblogs.com/juniorMa/p/14087517.html