spring为什么要使用三级缓存解决循环依赖

一 spring为什么要使用多级缓存

首先清楚spring中bean 的加载过程:

1 解析需要spring管理的类为beanDefinition

2 通过反射实例化对象

3 反射设置属性

4初始化,调用initMethod等。(postConstruct也是在这执行)

循环依赖的问题: a依赖b,b依赖a。

在a实例化之后会先将a放入到缓存中,然后给a设置属性,去缓存中查到b。此时找不到就开始b的创建。b实例化之后,放入到缓存中,需要给a设置属性,此时去缓存中查到a设置成功。然后初始化。成功后将b放入一级缓存。这个时候a在给自己属性b设置值的时候就找到了b,然后设置b。完成属性设置,再初始化,初始化后a放入一级缓存。

二 为什么要使用三级缓存

解决代理对象(如aop)循环依赖的问题。

例: a依赖b,b依赖a,同时a,b都被aop增强。

首先明确aop的实现是通过 postBeanProcess后置处理器,在初始化之后做代理操作的。

为什么使用三级缓存原因:

1 只使用二级缓存,且二级缓存缓存的是一个不完整的bean

如果只使用二级缓存,且二级缓存缓存的是一个不完整的bean,这个时候a在设置属性的过程中去获取b(这个时候a还没有被aop的后置处理器增强),创建b的过程中,b依赖a,b去缓存中拿a拿到的是没有经过代理的a。就有问题。

2 使用二级缓存,且二级缓存是一个工厂方法的缓存

如果二级缓存是一个工厂的缓存,在从缓存中获取的时候获取到经过aop增强的对象。可以看到从工厂缓存中获取的逻辑。

protected ObjectgetEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {

Object exposedObject = bean;

  if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {

for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bpinstanceof SmartInstantiationAwareBeanPostProcessor) {

SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;

            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);

        }

}

}

return exposedObject;

}

a依赖b,b依赖a,c。c又依赖a。a,b,c均aop增强。

加载开始: a实例化,放入工厂缓存,设置b,b实例化,设置属性,拿到a,此时从工厂缓存中拿到代理后的a。由于a没加载完毕,不会放入一级缓存。这个时候b开始设置c,c实例化,设置属性a,又去工厂缓存中拿对象a。这个时候拿到的a和b从工厂缓存不是一个对象。出现问题。

3 使用二级缓存,二级缓存缓存的是增强后的bean。这个与spring加载流程不符合。spring加载流程是:实例化,设置属性,初始化,增强。在有循环引用的时候,之前的bean并不会增强后放入到二级缓存。

综上1,2,3 可知二级缓存解决不了有aop的循环依赖。spring采用了三级缓存。

三 spring的三级缓存

一级缓存  singletonObjects    缓存加载完成的bean。

二级缓存  earlySingletonObjects 缓存从三级缓存中获取到的bean,此时里面的bean没有加载完毕。

三级缓存 singletonFactories 。缓存一个objectFactory工厂。

场景:a依赖b,b依赖a和c,c依赖a。并且a,b,c都aop增强。

加载过程:

a实例化,放入三级工厂缓存,设置属性b,b实例化放入三级缓存。b设置属性a,从三级工厂缓存中获取代理后的对象a,同时,代理后的a放入二级缓存,然后设置属性c,c实例化放入三级缓存,设置属性a,此时从二级缓存中获取到的代理后的a跟b中的a是一个对象,属性a设置成功。c初始化,然后执行后置处理器。进行aop的增强。增强后将代理的c放入到一级缓存,同时删除三级缓存中的c。c加载完成,b得到c,b设置c成功。b初始化,然后执行后置处理器,进行aop增强,将增强后的代理对象b放入到一级缓存。删除三级缓存中的b。此时 a拿到b,设置属性b成功,开始初始化,初始化后执行后置处理器。在aop的后置处理器中有一个以beanName为key,经过aop增强的代理对象为value的map earlyProxyReferences。

这个时候 后置处理器处理对象a的时候,

public ObjectpostProcessAfterInitialization(@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;

}

也就是 发现这个beanName已经被代理后就不在代理。这个时候执行后置处理器后,a还是未经代理的对象a。此时a再通过getSingleton 重新从缓存中获取一下a。

Object earlySingletonReference = getSingleton(beanName, false);

false 表示不从三级缓存中取,只从一级,二级缓存中获取。

这个时候能拿到二级缓存中的a。二级缓存中的a也是经过代理后的a。

然后将代理后的a放入到一级缓存中。a加载完毕。

放入一级缓存的过程 :

addSingleton(beanName, singletonObject);

从三级工厂缓存中获取对象:

protected ObjectgetEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {

Object exposedObject = bean;

  if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {

for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bpinstanceof SmartInstantiationAwareBeanPostProcessor) {

SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;

            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);

        }

}

}

return exposedObject;

}

其中 AbstractAutoProxyCreator实现该接口。

public ObjectgetEarlyBeanReference(Object bean, String beanName) {

Object cacheKey = getCacheKey(bean.getClass(), beanName);

  this.earlyProxyReferences.put(cacheKey, bean);

  return wrapIfNecessary(bean, beanName, cacheKey);

}

wrapIfNecessary()就是真正执行代理的。

bean初始化之后执行的后置处理器:


spring为什么要使用三级缓存解决循环依赖_第1张图片
bean后置处理器

其中AbstractAutoProxyCreator 实现了该接口。


spring为什么要使用三级缓存解决循环依赖_第2张图片

你可能感兴趣的:(spring为什么要使用三级缓存解决循环依赖)