Spring循环依赖使用三级缓存,源码原理分析

97 阅读3分钟

模拟案例:

ServiceA注入ServiceB,ServiceB注入ServiceA,下列代码首先创建Bean:ServiceA,ServiceA会依赖注入ServiceB,整体依赖注入流程如下:

判断当前bean是否在创建的关键在于

DefaultSingletonBeanRegistry类中的 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) 调用的beforeSingletonCreation(beanName)方法放入当前bean正在创建。

protected void beforeSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}
  1. 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));
}

() -> getEarlyBeanReference(beanName, mbd, bean)是传入一个实现类方法,实现了ObjectFactory接口的getObject()方法。

2.进行属性注入,doCreateBean中调用方法注入ServiceB

populateBean(beanName, mbd, instanceWrapper);

3.调用DefaultListableBeanFactory类的方法doResolveDependency:

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter)

调用链路中,方法走向最后具体执行代码是:

if (instanceCandidate instanceof Class) {
   instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}

4.发现ServiceB未实例化,调用DependencyDescriptor类的方法开始重新执行getBean创建ServiceB:

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
      throws BeansException {

   return beanFactory.getBean(beanName);
}

以上就是循环依赖整体流转的核心流程。

**1) 核心思想流程:

  1. A初始化过程中先将自己放入三级缓存,A属性注入B,B执行初始化,首先也是放入三级缓存,B属性注入A,在获取A的时候将A从三级缓存移入二级缓存并返回(返回的对象可能是AOP代理后的对象,是与不是取决于当前注入的A是否有代理的需求,调用:getEarlyBeanReference方法判断是否代理),此时B注入A成功。
  2. B执行完整的Spring生命周期后(也可能是个AOP对象,这里执行的BeanPostProcessor后置方法进行AOP代理判断:关键点在于当前bean是否被其他bean注入的时候是否执行过aop代理的代码,也就是getEarlyBeanReference()方法是否执行过,因为执行过会在AOP代理类的缓存中存在: this.earlyProxyReferences.remove(cacheKey) != bean 这里判断是否代理过,没代理过才执行aop代理操作,否则直接返回bean)放入一级缓存并将二级三级缓存中的B删除,并递归返回到A注入B,从一级缓存中拿到B,并注入成功。 **

2) 三级缓存的意义:为了注入的是代理对象!

  1. 核心代码在AbstractAutoProxyCreator类中:
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
   Object cacheKey = getCacheKey(bean.getClass(), beanName);
   //缓存当前bean,证明自己被代理执行过了
   this.earlyProxyReferences.put(cacheKey, bean);
   //返回代理对象:如果当前对象有代理需求,没有就直接返回当前bean
   return wrapIfNecessary(bean, beanName, cacheKey);
}

在获取三级缓存的时候,ObjectFactory接口执行getObject方法:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // Quick check for existing instance without full singleton lock
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            // Consistent creation of early reference within full singleton lock
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     //执行是否进行代理的操作,最终执行的是getEarlyBeanReference()方法
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}
  1. 每个bean的生命周期最后会执行BeanPostProcessor的后置通知方法postProcessAfterInitialization(),从代理实现类中移除当前bean,只有在初始化中没:
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      //如果当前bean不存在缓存中,也就是没被代理过
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
          //则选择aop代理:代理与不代理取决于当前bean是否有需求
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}