攀爬Spring珠穆拉玛峰:preInstantiateSingletons方法、三级缓存、循环依赖

1)Spring 三级缓存与循环依赖

本文将以DefaultListableBeanFactory#preInstantiateSingletons方法为切入点,主要整理有关三级缓存和循环依赖的问题。

下面简单的回顾一下之间的流程,详细内容参看另一篇文章:Spring启动流程

前文回顾

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    register(componentClasses);
    refresh();
}

同样用简图来描述流程
在这里插入图片描述

preInstantiateSingletons

@Override
public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    //初始化所有非懒加载的单例Bean
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged(
                            (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                            getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                       ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                getBean(beanName);
            }
        }
    }

    //在BeanFactory引导期间的单例预实例化阶段结束时触发的回调接口。 该接口可以由单例 bean 实现,
    //以便在常规单例实例化之后执行一些初始化,避免意外早期初始化(例如来自ListableBeanFactory.getBeansOfType调用)的副作用。
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}
  1. 迭代所有的BeanDefinitionNames集合,挨个初始化所有非懒加载的单例类。

  2. BeanDefinitionNames是在注册BeanDefinitionMap时同时注册的集合。该集合,主要用在这里进行迭代初始化Spring Bean,并且也方便一些类似获取BeanDefinitionName的方法使用。

  3. 初始化的时候还对FactoryBean进行判断,因为默认FactoryBean默认是惰性初始化,如果实现SmartFactoryBean设置isEagerInit为true,则代表该类需要急切的进行初始化,会即刻开始初始化FactoryBeangetObject返回的类。

  4. 关于getMergedLocalBeanDefinitiongetBean:Spring通过getBean来完成类的初始化并添加到Spring容器内(即Spring的一级缓存:单例池里面),而在初始化时需要当前类的相关信息:即BeanDefinition,而BeanDefinition是可以存在父子关系(并非真的继承,而是BeanDefinition可以设置父BeanDefinition),所以Spring通过getMergedLocalBeanDefinition来获取当前类的完整信息。

getBean→doGetBean

getBean内继续进行方法调用,最终进入到doGetBean里面,

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
				...
 			    ...
				// 创建Bean.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							//创建Bean
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}	
    			...
 			    ...

	}

先简单总结一下省略部分的代码作用:

  • 尝试从单例池(一级缓存)中获取,如果能获取则直接返回。
  • 检查@DependsOn注解,如果当前类依赖于@DependsOn标注的类,则先初始化被依赖的类。
  • 标记当前类的状态
  • 各种参数的合法性校验
  • 针对prototype类型Bean的相关处理

最终调用getSingleton完成Bean的初始化。先整理一下与接下来的分析相关的概念。

自动装载与循环依赖

在Spring中我们通过@Autowired@Resource,完成一个Spring Bean注入到另外一个Spring Bean中的,这个过程被我们称之为自动装载。

那么Spring是怎样将两个Bean都存储在单例池中,并且完成引用的呢?如果是简单的先存后拿,肯定是不行的。因为存在特殊情况:

在这里插入图片描述

即在类A中依类B,类B依赖类A。单纯的考虑,加载A→判断依赖B→加载B→判断依赖A→加载A……

按照一般的思路就会发生上面的情况,出现了死循环。Spring在一定程度上是支持循环依赖的。对应的方案是引入了三级缓存。

三级缓存

DefaultListableBeanFactory的父类链上的DefaultSingletonBeanRegistry定义了三个缓存池:

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
  • singletonObjects:单例池,通常意义上的Spring容器,Spring在这个池中存放已经初始化完毕的Spring Bean;
  • earlySingletonObjects:存放提前暴露并且经过代理的单例类,
  • singletonFactories:存放ObjectFactory,而ObjectFactorygetObject方法定义了如何获取早期的Bean引用。

getSingleton

下面进入代码解析:getSingleton

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                  "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
         }
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // 如果在创建bean期间隐式出现了对应的资源(即发现此时已经添加进入了单例池,则抛出异常)
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throw ex;
            }
         }
         catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) {
                  ex.addRelatedCause(suppressedException);
               }
            }
            throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            //如果获取到了新的Bean实例(已经完成了代理和自动装载),则添加进单例池中
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

doGetBean里面调用getSingleton方法时,利用到了lambda的特性来作为入参。先逐行观察getSingleton

主要的代码是beforeSingletonCreation(beanName)。这行代码很重要:将单例注册为当前正在创建中。

然后是调用ObjectFactorygetObject方法,即之前lambda定义的内容:return createBean(beanName, mbd, args)

createBean

点进createBean方法。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   if (logger.isTraceEnabled()) {
      logger.trace("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDefinition mbdToUse = mbd;

  //推断当前Beandefinition的beanClass
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   // 准备方法重写 包括lookup-method和replaced-method的处理,本文暂不展开
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
      // 第一次调用后置处理器:初始化Bean之前,InstantiationAwareBeanPostProcessor,
      // 根据BeanDefinition获取到了对应的class类
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }

   try {
      //创建Bean
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}

createBean里面完成了第一次后置处理器的调用。关于后置处理器本文暂不展开,并且调用了doCreateBean方法。

doCreateBean方法代码较长,并且是spring处理循环依赖的重要部分,我们拆分开来分析。

doCreateBean

推断构造函数并利用反射创建
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
            //从未完成的 FactoryBean 实例中移除
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//实例化对象(仅仅是生成对象,并非添加到spring单例池中,即目前并没有成为Spring Bean),
			//并且第二次调用 后置处理器 determineConstructorsFromBeanPostProcessors
 			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
    
 		... 
     	...  
     	...   
}

首先通过createBeanInstance方法调用后置处理器推断其构造函数,并反射创建BeanDefinition对应的实例。

  • 注意此时只是创建了类对象,但还没有添加到Spring的单例池中,即还没有加入到Spring容器内部。
  • 可以理解为此时只是完成了类对象的声明:即类似于A a=null

Spring 解决循环依赖的原理就在于java类可以先声明,再实例化

新增ObjectFactory到第三级缓存

继续分析doCreateBean

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    	throws BeanCreationException {
        ...
        ...
        //允许后置处理器重新定义beanDefinition
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					//第三次调用后置处理器 MergedBeanDefinitionPostProcessors
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		//判断是否允许循环依赖,默认是允许的,可以通过代码修改的一般只有allowCircularReferences的值
		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");
			}
			// getEarlyBeanReference里面包含了又一次后置处理器的调用,SmartInstantiationAwareBeanPostProcessor 
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
}

调用了两次后置处理器,并且根据earlySingletonExposure判断当前项目是否允许循环依赖。

earlySingletonExposure由三个值判断:

  • 当前创建类是否是单例类
  • allowCircularReferences是否为true,即当前是否允许循环依赖。注意此参数是可以由程序员手动修改的,即Spring允许程序员自行决定程序中是否允许出现循环依赖
  • isSingletonCurrentlyInCreation(beanName):需要当前类处于创建状态,在前文getSingletonbeforeSingletonCreation(beanName)中已经设置为 创建中状态
属性填充:populateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        //填充属性(即自动注入) 完成第五次和第六次后置处理器的调用
        // InstantiationAwareBeanPostProcessor.after
        // hasInstantiationAwareBeanPostProcessors
        populateBean(beanName, mbd, instanceWrapper);
        //完成第七次和第八次后置处理器的调用,
        //判断当前Bean,是否是BeanNameAware、BeanClassLoaderAware、BeanFactoryAware并分别设置相关内容
        //applyBeanPostProcessorsAfterInitialization
        //applyBeanPostProcessorsAfterInitialization
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        }
        else {
            throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
        }
    }
}

populateBean方法完成属性填充,跟进。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   if (bw == null) {
      if (mbd.hasPropertyValues()) {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
         // Skip property population phase for null instance.
         return;
      }
   }

  //在设置属性之前,让任何 InstantiationAwareBeanPostProcessors 有机会修改 bean 的状态。例如,这可用于支持字段注入样式。
  //扩展点,又一次调用后置处理器,
   boolean continueWithPropertyPopulation = true;

   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }

   if (!continueWithPropertyPopulation) {
      return;
   }
   //如果后置处理器修改了Beandefinition,则判断是否已经修改过了属性值的相关配置
   //如果修改了,则按照器byName或byType的方式直接完成装载
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

   [] filteredPds = null;
   if (hasInstAwareBpps) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            //利用后置处理器,处理属性的获取
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               if (filteredPds == null) {
                  filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
               }
               pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvsToUse == null) {
                  return;
               }
            }
            pvs = pvsToUse;
         }
      }
   }
   if (needsDepCheck) {
      if (filteredPds == null) {
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }

   if (pvs != null) {
      //根据PropertyValues完成属性填充
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

populateBean里面再次调用后置处理器,spring在这里提供了一个扩展点,允许开发者在属性填充这个阶段修改Bean的状态(使用后置处理器的方式)。并且可能直接依据byNamebyType装载属性值。

我们知道,使用自动装载这一功能时,我们可以使用@Autowired@Resource。这两个注解的功能也不一样。那么解析的方式也应当不一样。

这里,提出一个老生常谈的问题:

@Autowired@Resource的联系与区别

从功能层面,也是最简单的层面来看:

  • @Autowired@Resource都是完成自动装载的注解
  • @Autowired装载时默认是byType注入的,byType时如果存在多个结果,使用@Primary标注的类。想要使用byName注入,则需要配合@Qualifer注解
  • @Resource默认按照byName注入,如果不匹配,则会回退为原始类型进行匹配。并且@Resource可以同时支持byNamebyType

从解析层面,也是更深刻的层面来看:

  1. spring在完成属性填充(自动装载)时利用后置处理器来解析,会调用后置处理器的postProcessProperties方法。
  2. 而解析@Autowired@Resource的后置处理器也是不一样的。这点很容易理解,毕竟二者存在使用上的区别,自然不可能使用同一套代码来完成解析。

@Resource:使用CommonAnnotationBeanPostProcessor后置处理器解析

@Autowired:使用AutowiredAnnotationBeanPostProceoor后置处理器解析

前面提到正常来说完成自动装载应当有以下步骤:加载A→判断依赖B→加载B→判断依赖A→加载A……

spring即是在上面提到的两个后置处理器里面完成了上面的步骤。我们以A依赖B,B依赖A的情况来做分析。

后置处理器获取或加载属性

AutowiredAnnotationBeanPostProceoor为例(假定A中的成员变量B为@Autowired的Setter注入)跳到关键代码如下:

DefaultListableBeanFactory#doResolveDependency

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

...
...
...
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
    throws BeansException {
    return beanFactory.getBean(beanName);
}    

此时是在AutowiredAnnotationBeanPostProceoor内部加载时,发现A依赖B,并通过getBean获取B。

注意此时B是还没有初始化的,即在Spring的单例池中并不存在。

那么此时经过getBean的调用,B也将进行一次上面A的加载步骤:

  1. 推断构造函数创建B,封装到BeanWrapper
  2. 新增B的ObjectFactory到第三级缓存
  3. 属性填充,AutowiredAnnotationBeanPostProceoor获取B的属性。

矛盾点来了:此时B的属性经判断时A,此时A还没有完成初始化,难道再次创建A吗,这无疑造成了死循环。

我们来看看Spring是如何处理:

//尝试获取
Object sharedInstance = getSingleton(beanName);
@Override
@Nullable
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
...
...
...    
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //尝试从一级缓存单例池取
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            //从二级缓存里面取
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                //如果二级缓存没取到,则从三级缓存里面取
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    //三级缓存移动到二级缓存
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

getBean调用时会调用getSingleton尝试获取,在B的后置处理器内获取A时,进入到方法内部。

有3个重要点:创建中状态、第三级缓存(ObjectFactory)、allowEarlyReference(是否允许获取早期引用)

this.singletonObjects.get(beanName):尝试从一级缓存单例池取,此时A没有创建完毕,自然获取不到

this.earlySingletonObjects.get(beanName):先判断是否处于创建中状态,如果是的话,则可以从二级缓存里面取。

  • 前面提到A在最开始getBean的时候已经在getSingleton(String beanName, ObjectFactory<?> singletonFactory)beforeSingletonCreation(beanName)里面设置了A为创建中状态

此时依旧无法获取到A,二级缓存中不存在。

this.singletonFactories.get(beanName):allowEarlyReference为true,此时尝试从三级缓存里面获取。调用三级缓存ObjectFactory.getObject()方法。成功获取到A,并将三级缓存移动到二级缓存。

此时成功创建了B,再度回到A的创建过程当中。

调用initializeBean
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
  • invokeAwareMethods:如果当前类是BeanNameAwareBeanClassLoaderAwareBeanFactoryAware则设置相关属性;调用初始化方法
  • 调用两次后置处理器
判断Bean版本问题

正常来说,到这里就结束了。不过spring还进行了额外的判断。同样是循环依赖的收尾问题。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
    ...
    ...
    ...    
  	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				// allowRawInjectionDespiteWrapping:在循环引用的情况下是否诉诸于注入原始 bean 实例,即使注入的 bean 最终被包裹
				// 如果当前创建的bean出现在了二级缓存里面,证明出现了循环引用
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					//获取当前bean 依赖的bean
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							//如果在已经创建了对应的依赖
							actualDependentBeans.add(dependentBean);
						}
					}
					//存在已经创建的依赖,即当前bean已经被引用它的bean 使用了。
					// 即当前bean已经被装载了,但是此刻的bean被修改了。(例如 在initializeBean的后置处理器重新new,或生成了另外一个代理)
					// 证明初始当前bean出现了版本差异
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}  
}
  1. 首先是判断当前是否支持循环依赖
  2. 如何支持的话,就尝试是否能获取到当前对象,调用getSingleton(beanName, false)注意第二个参数allowEarlyReference为false,这表明只从二级缓存里面去取(此时本类尚处于创建中,一级缓存里面是肯定没有的,所以实际上就是从二级缓存里面去取)

为什么要从二级缓存里面去取?

  • 正常情况下,spring的二级缓存只有一个途径新增,那就是从三级缓存移动过来,此时会调用三级缓存内的ObjectFactory#getObject,最终调用getEarlyBeanReference。在这里面可能会进行aop的代理,即最终到达二级缓存里面的对象是经过代理的(如果该类需要被代理的话)

那么什么时候会移动三级缓存到二级缓存?

  • 答案是出现循环依赖的时候,老例子A和B,初始化B的时候,需要获取A,而A正在创建中,此时就需要从三级缓存里面获取。

所以,之所以要从二级缓存里面去取 是为了验证当前类是否出现了循环依赖

那么上面一长段代码的作用就很明显了:

用A和B举例

  1. 验证当前创建的A对象,是否已经被其他对象给依赖注入了。
  2. 如果是的话,那么当前A类是否被代理过了,如果代理了,那么B里面的A对象和经过initializeBean之后的对象是否为同一个?
  3. 是的话,直接返回。不是的话,根据allowRawInjectionDespiteWrapping的值判断,是否抛出异常。

总的来说就是为了确保是否要在循环引用的情况下,是否仍要在单例池里面增加当前对象。其实还是为了解决aop代理的问题。

回到getSingleton方法,添加到单例池里面

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
                //标记当前类为 正在创建中
				//设置当前初始化类 到set集合中,如果不能添加就直接报错 (set 不能重复添加)
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					//通过createBean方法新创建的对象
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					//清除二三级缓存,新增当前实例到一级缓存单例池
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

好家伙,经历了漫长的调用栈,差点忘记上面所有的代码只是调用了getSingleton#singletonFactory.getObject()而已。

此时singletonObject = singletonFactory.getObject()获取到的singleObject已经是完全创建好的对象了。

调用addSingleton方法,直接放到spring的以及缓存里面即可。

注意:此时addSingleton会清除二三级缓存里面的值。

  • 如果没有发生循环依赖,三级缓存里面始终有一份当前beanName的缓存。
  • 或者类似于初始化B时,B获取A时,能够从A的二级缓存获取到。但是B本身还是始终在三级缓存里面有一份的,这种情况三级缓存里面也有
  • 如果发生了循环依赖,则存在于二级缓存,(因为A初始化的时候被引用,从三级缓存跳到了二级缓存)

ok,初始化完毕

2)其他问题

开发者可以设置的两个特别变量

  • allowEarlyReference:当出现循环依赖的时候,是否允许提前获取引用(从三级缓存里面获取)

  • allowRawInjectionDespiteWrapping:出现循环依赖时,是否仍要在单例池里面增加当前对象

这两个变量都是可以设置的,如下:

@Configuration
@ComponentScan("com.sulin")
@EnableAspectJAutoProxy
public class AppConfig {

}

class StartApplication {
	public static void main(String[] args) throws InterruptedException {
        //注册BeanDefinition,设置两个变量,并手动refresh
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
        AbstractAutowireCapableBeanFactory beanFactory = (AbstractAutowireCapableBeanFactory) ac.getBeanFactory();
        beanFactory.setAllowCircularReferences(false);
        beanFactory.setAllowRawInjectionDespiteWrapping(false);
        ac.register(AppConfig.class);
        ac.refresh();
    }
}

为什么需要三级缓存?二级缓存可以吗?

答案:可以,但没必要。

  • 我们这里说的二级缓存指的是,一级缓存和三级缓存,即单例池和ObjectFactory缓存。
  • 确实一级+三级缓存就足够解决循环依赖。二级缓存只是存的从三级缓存ObjectFactory获取到的对象而已。
  • 那么不存到二级缓存,每次直接从三级缓存getObject也是可以的。就算是存在AOP代理。到时候再执行一次就可以了。

事实上,在较早期的spring版本中就是二级缓存。中间的一层是后面的版本再加进去的。

三级缓存的getEarlyBeanReference包含后置处理器进行代理(AOP),中间再加一层,提高了效率,不必每次都去进行后置处理器的代码调用。设计上面来说也更加科学。

3)流程案例总结

简单整理一下存在循环依赖时和不存在循环依赖时整体的过程。

存在循环依赖:例如AB互相依赖

  1. 通过getBean获取 A 时,将 A 相关的ObjectFactory添加进三级缓存,设置 A 当前状态为为创建中状态;
  2. 通过Beandefinition进行构造器推断,反射创建出 A 的Java对象,封装到WrappedInstance;
  3. 进行 A 的属性填充,发现需要注入B对象(根据@Resource或@Autowired判断),尝试获取 B
  4. 通过getBean(B)获取 B 时,将 B 相关的ObjectFactory添加进三级缓存,设置 B 当前状态为为创建中状态
  5. 通过Beandefinition进行构造器推断,反射创建出 B 的Java对象,封装到WrappedInstance;
  6. 进行 B 的属性填充,发现需要注入 B 对象(根据@Resource或@Autowired判断),尝试获取 A;
  7. 此时因为 A 处于创建中状态,并且allowEarlyReference为true,便从三级缓存拿 A此时如果A需要代理,遍会调用后置处理器进行AOP相关操作),移动到二级缓存,A 从三级缓存移动到二级缓存。B 成功获取到 A 的引用。
  8. B 初始化完毕,在 getSingleton方法中进行资源清理,将新的 B对象添加到一级缓存当中,并从三级缓存里面移除 B ;
  9. 回到 A,此时 A 通过getBean(B)成功获取到 B
  10. A 初始化完毕,在 getSingleton方法中进行资源清理,将新的 A对象添加到一级缓存当中,并从二级缓存里面移除 B

流程图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值