Java-第十五部分-源码解读-循环依赖梳理

251 阅读4分钟

源码解读全文

循环依赖

发生原因

  • ABean赋值环节populateBean,需要BBean,通过getBeanNamesForType找到匹配到的BBean后,需要通过getBean获取,那么就需要创建BBean,而此时BBean,根据同样的步骤,获取AABean,产生了循环注入
  • 由于BBean中需要的是完整代理处理后的ABean,那么就需要提前对ABean进行代理处理,才能放入BBean
  • 而由于,cglib中的代理对象包含一个普通对象,那么就可以保证引用不变的情况下,先将包装成代理对象ABean注入BBean,解决完循环依赖后,再对ABean完成剩下的注入流程

解决循环依赖,回到ABeancreateBean的流程中时,此时赋值处理的仍然是ABean的普通对象,而这个普通对象此时也被注入到BBean中的ABean的代理对象所持有,那么也可以保证ABean中的普通对象,是完整的

前提准备

加入singletonsCurrentlyInCreation

  • getSingletonbeforeSingletonCreation(beanName);
  1. 其中会有double-check
protected void beforeSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

加入三级缓存

  • 完成instanceWrapper = createBeanInstance(beanName, mbd, args);,创建一个实例后,进行循环依赖解决的准备,支持循环依赖就会被放入三级缓存
// earlySingletonExposure 标志位
// 是单例 && 可以自动解决循环依赖 && 是在创建过程
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");
   }
   //加入三级缓存,采用`lambda`表达式,加入的工厂类
   //最终通过`getEarlyBeanReference`,获取到三级缓存的对象,也会被后置处理增强
   addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
  • addSingletonFactory,加入的是singletonFactory
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);
      }
   }
}
  • ObjectFactory工厂接口
public interface ObjectFactory<T> {
   T getObject() throws BeansException;
}
  • getEarlyBeanReference
  1. 过程中wrapIfNecessary(bean, beanName, cacheKey);,生成代理对象
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
         exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
      }
   }
   return exposedObject;
}

避免重复生成代理对象

  • getEarlyBeanReference,将Bean记录在earlyProxyReferences
public Object getEarlyBeanReference(Object bean, String beanName) {
   Object cacheKey = getCacheKey(bean.getClass(), beanName);
   this.earlyProxyReferences.put(cacheKey, bean);
   //生成代理对象
   return wrapIfNecessary(bean, beanName, cacheKey);
}

三级缓存的解决

  • 一级也能解决,但是三级更有层次感
  1. 用标识符来表示
  2. >表示刚刚实例化;@表示完整对象
  • singletonObjects一级缓存,单例池
  • earlySingletonObjects二级缓存,保存提前生成的代理对象,便于后边比较,防止重复生成,保证单例
  • singletonFactories三级缓存,以ObjectFactory的形式,保存早期实例化的Bean,以直接获取代理对象
  • earlyProxyReferences保存已经进行代理处理过的Bean防止重复处理
  • singletonsCurrentlyInCreation开始创建前保存,判定循环依赖的标志

细节

  • getBean过程中,会先检查缓存,并允许早期引用,从其他缓存中获取

发生循环依赖时,三级缓存中是存在的,因此,就从三级缓存的工厂类中,注入早期的引用Bean,此时这个Bean还没有完成赋值和初始化

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 检查单例池缓存,一级缓存是否有当前对象
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && 
   //  是否正在创建,那么就发生了循环依赖
   isSingletonCurrentlyInCreation(beanName)) {
       // 从二级缓存中获取
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
             //double-check,一级缓存
            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) {
                      //调用`getObject`
                     singletonObject = singletonFactory.getObject();
                     //生成的代理对象放入二级缓存
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

后续处理

  • 解决以上方案带来的影响

提早生成了代理对象

避免重复代理处理

  • 回到createBean的流程中的exposedObject = initializeBean(beanName, exposedObject, mbd);,调用后置处理器
  • wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);,如果需要代理处理时,调用AbstractAutoProxyCreator.postProcessAfterInitialization,过程中检查earlyProxyReferences
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;
}

返回Bean的比较

  • 如果发生循环依赖,引起循环依赖的Bean存在于二级缓存中
if (earlySingletonExposure) {
    //能从二级缓存中获取到,传入 false 只能从二级缓存中获取
   Object earlySingletonReference = getSingleton(beanName, false);
   if (earlySingletonReference != null) {
       //exposedObject 该对象接受了赋值/后置处理器/初始化的处理
       //如果在处理过程中,导致该对象引用改变,被包装成代理对象,那么此时就不符合原则
       //没有发生变化,那么直接返回二级缓存中的代理对象
      if (exposedObject == bean) {
         exposedObject = earlySingletonReference;
      }
      else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
         String[] dependentBeans = getDependentBeans(beanName);
         Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
         for (String dependentBean : dependentBeans) {
            if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
               actualDependentBeans.add(dependentBean);
            }
         }
         // ...
      }
   }
}