你所不知道的一些关于Spring如何解决循环依赖的细节

752 阅读18分钟

什么是循环依赖?

顾名思义,就是假设有bean A和bean B,A的实例化依赖于B实例的存在,B的实例化也必须依赖于A实例的存在。如果没有相关的处理方案,肯定是会陷入死循环的。那么Spring是如何来解决这个问题的呢?

我们直接进入正题,开始源码解读,首先找到AbstractApplicationContext的refresh()方法。

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 为刷新准备此上下文,设置它的启动日期和活动标志,并执行任何初始化的属性源。
      prepareRefresh();

      //告诉子类刷新内部beanFactory,如果之前有老的beanFactory就先关闭,然后初始化一个新的beanFactory。
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      //准备beanFactory以供在此上下文中使用,主要是加载一些beanFactory的配置
      prepareBeanFactory(beanFactory);

      try {
         //加载bean的定义,但不会实例化bean。
         postProcessBeanFactory(beanFactory);

         //在单例实例化之前,实例化并调用所有注册过的BeanFactoryPostProcessor
         invokeBeanFactoryPostProcessors(beanFactory);

         //在应用程序的bean实例化之前,实例化并调用所有的BeanFactoryPostProcessor
         registerBeanPostProcessors(beanFactory);

         //初始化信息源,如果在上下文内没有定义,就用parent的。
         initMessageSource();

         //初始化ApplicationEventMulticaster,如果在上下文内没有定义,就直接用SimpleApplicationEventMulticaster
         initApplicationEventMulticaster();

         // 初始化其他在特定上下文子类中的特殊的bean。
         onRefresh();

         //注册监听器的bean。
         registerListeners();

         //初始化所有剩余的单例bean,完成这个上下文的beanFactory的初始化,可以看到这里是核心代码
         finishBeanFactoryInitialization(beanFactory);

         //完成此上下文的刷新,调用LifecycleProcessor的方法并发布,这是最后一步操作。
         finishRefresh();
      }
      catch (BeansException ex) {
         //和核心功能无关的代码处理
      }
      finally {
         //和核心功能无关的代码处理
      }
   }
}

然后重点关注finishBeanFactoryInitialization(beanFactory)方法,因为其他方法都不涉及到单例的延迟加载。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // Initialize conversion service for this context.
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }

   // Register a default embedded value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }

   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);

   // Allow for caching all bean definition metadata, not expecting further changes.
   beanFactory.freezeConfiguration();

   //初始化所有剩余的单例bean
   beanFactory.preInstantiateSingletons();
}

前面的代码都可以忽略不看,你一眼就能看到beanFactory.preInstantiateSingletons()这个方法的注释和finishBeanFactoryInitialization的注释一模一样,显然这就是该方法的核心处理逻辑。

这里说下阅读源码的偷懒方式,可以先看注释,大概明白讲什么,然后再一一仔细读,这样可以跳过很多边缘的非核心的处理逻辑。

public void preInstantiateSingletons() throws BeansException {
   if (logger.isTraceEnabled()) {
      logger.trace("Pre-instantiating singletons in " + this);
   }
   // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   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) {
               final 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);
         }
      }
   }

   // Trigger post-initialization callback for all applicable beans...
   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         }
         else {
            smartSingleton.afterSingletonsInstantiated();
         }
      }
   }
}

这个方法,上半段主要讲的是如何初始化所有非Lazy加载的单例bean,下半段主要讲的是所有适用的bean加载后触发回调。显然核心主要还是上面一块。

然后看for循环内的代码,对所有beanNames对遍历,然后根据beanName获取到对应的RootBeanDefinition(如果是子bean,那么这个bean的定义需要和parent的bean合并)。

再看第一个if判断,只要这个bean符合非抽象,是单例,非懒加载这三条就满足条件。

然后第二个if判断,无非是判断下这个bean到底是不是FactoryBean(本质上还是bean,一个能生产对象的工厂bean)。这都不管见,关键的方法还是getBean(beanName),因为你看即便是FactoryBean,兜兜转转一系列操作之后满足条件最后的操作还是这个getBean方法。

getBean方法,底层就是doGetBean。我们不妨直接看doGetBean方法吧。

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else {
		// Fail if we're already creating this bean instance:
		// We're assumably within a circular reference.
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// Check if bean definition exists in this factory.
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// Not found -> check parent.
			String nameToLookup = originalBeanName(name);
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			}
			else if (args != null) {
				// Delegation to parent with explicit args.
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else if (requiredType != null) {
				// No args -> delegate to standard getBean method.
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
			else {
				return (T) parentBeanFactory.getBean(nameToLookup);
			}
		}

		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}

		try {
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// Guarantee initialization of beans that the current bean depends on.
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					registerDependentBean(dep, beanName);
					try {
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			// Create bean instance.
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, () -> {
					try {
						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);
			}

			else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}

			else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					Object scopedInstance = scope.get(beanName, () -> {
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						}
						finally {
							afterPrototypeCreation(beanName);
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName,
							"Scope '" + scopeName + "' is not active for the current thread; consider " +
							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
							ex);
				}
			}
		}
		catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}

	// Check if required type matches the type of the actual bean instance.
	if (requiredType != null && !requiredType.isInstance(bean)) {
		try {
			T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
			if (convertedBean == null) {
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
			return convertedBean;
		}
		catch (TypeMismatchException ex) {
			if (logger.isTraceEnabled()) {
				logger.trace("Failed to convert bean '" + name + "' to required type '" +
						ClassUtils.getQualifiedName(requiredType) + "'", ex);
			}
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
	}
	return (T) bean;
}

然后大致浏览一边,看一下主体逻辑。首先是通过getSingleton(beanName)获取到sharedInstance,然后再判断sharedInstance是否存在。

如果存在,则通过getObjectForBeanInstance方法直接获取到我们所需要的bean。

如果不存在,我们则需要通过创建一个实例Instance,然后也是通过getObjectForBeanInstance方法获取到我们所需要的bean。

很显然,重点就是获取这个实例Instance的过程。我们先看下getSingleton部分的代码。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   //从singletonObjects里获取单例
   Object singletonObject = this.singletonObjects.get(beanName);
   //如果singletonObjects里面不存在singletonObject,且beanName对应的singleton bean正在被创建中
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         //从earlySingletonObjects里获取单例
         singletonObject = this.earlySingletonObjects.get(beanName);
         //如果earlySingletonObjects里面不存在singletonObject,且引用能够被提前创建
         if (singletonObject == null && allowEarlyReference) {
            //从singletonFactories里面获取对应的singletonFactory
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            //如果对应的singletonFactory存在
            if (singletonFactory != null) {
               //直接通过这个singletonFactory创建single bean的实例
               singletonObject = singletonFactory.getObject();
               //将这个singletonObject放到earlySingletonObjects中
               this.earlySingletonObjects.put(beanName, singletonObject); 
               //从singletonFactories清除对应的singletonFactory,因为在earlySingletonObjects已经存在对应的singletonObject,所以再也用不到从singletonFactories先获取singletonFactory,然后再通过singletonFactory创建single bean的实例
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

然后整理一下思路,整体的过程分为三步。
首先是singletonObjects,我们可以理解成一级缓存,这里的对应关系是beanName->singletonObject。

然后是earlySingletonObjects,我们可以理解成二级缓存,这里的对应关系是beanName->singletonObject。

最后是singletonFactories,我们可以理解成三级缓存,这里的对应关系是beanName->singletonFactory,singletonFactory是一个可以返回对象实例的工厂定义,singletonFactory.getObject()可以直接返回singletonObject。

是不是有点懵?你肯定在想,singletonObjects是什么时候有singletonObject缓存的?earlySingletonObjects又是什么时候有singletonObject缓存的? 而singletonFactories又是什么时候有singletonFactory缓存的?

首先是singletonObjects,我们先看它的put方法是哪里被调用的。搜索了一遍,发现了是在addSingleton(String beanName, Object singletonObject)方法内。

protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
   }
}

addSingleton的功能很简单,将singletonObject放入到一级缓存singletonObjects中,然后将二级缓存earlySingletonObjects内的对象清除,将三级缓存singletonFactories内的对象清除。

这个很好理解。一级缓存里面有对应的实例数据了,就压根用不着再去从二级和三级缓存内去获取对应的数据,这样可以节省一些缓存的空间。

然后,我们发现,addSingleton方法一共在两个方法内被调用了,一个是registerSingleton(String beanName, Object singletonObject),一个是getSingleton(String beanName, ObjectFactory<?> singletonFactory)。

public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
   Assert.notNull(beanName, "Bean name must not be null");
   Assert.notNull(singletonObject, "Singleton object must not be null");
   synchronized (this.singletonObjects) {
      Object oldObject = this.singletonObjects.get(beanName);
      if (oldObject != null) {
         throw new IllegalStateException("Could not register object [" + singletonObject +
               "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
      }
      addSingleton(beanName, singletonObject);
   }
}

我们先看registerSingleton方法内的逻辑,我们发现addSingleton方法调用的前提是singletonObjects里面已经存在对应beanName的oldObject了,他只是起到一个将入参的singletonObject替换原先singletonObjects已经存在的oldObject的作用。

我们可以断定,这里肯定不是最先将singletonObject放入到singletonObjects的方法。

那就只剩下一个getSingleton方法了,这个方法恰好只出现在doGetBean的创建实例Instance的方法内。

这么一来,我们有理由推断,在doGetBean方法内创建实例Instance之后,会将实例对象写入到一级缓存singletonObjects内。

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) {
            // 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;
   }
}

然后是earlySingletonObjects,我们依然先看下它的put方法是哪里被调用的。我们发现,它恰好只在上文提到的getSingleton(String beanName, boolean allowEarlyReference)方法内出现。

那这个就很好理解了,earlySingletonObjects的缓存只会出现在singletonFactories中有对应beanName的singletonFactory的场合下且这个引用允许被提前创建的时候。

我们可以推断下,其实earlySingletonObjects内只是存了一个singletonObject的引用,具体singletonObject是怎么样的,还是要看singletonFactory如何创建实例对象的。所以关键点还是要看singletonFactories的缓存数据是如何创建的。

然后我们一查,发现只有在addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)方法内才调用了singletonFactories的put方法。

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);
      }
   }
}

这个也很好理解,如果一级缓存singletonObjects内不存在对应的singletonObject,则将对应的singletonFactory放到三级缓存singletonFactories内,然后同时将二级缓存内的的对象清除。

因为如果不清理earlySingletonObjects内的缓存对象,将singletonFactory放入到三级缓存singletonFactories内将毫无意义,它必然会先从earlySingletonObjects找到对应的缓存对象。

同理,一级缓存对象singletonObjects里已经存在对应beanName的singletonObject,就没必要再多次一举走一遍singletonFactory的getObject方法。

这里你可能会疑惑,为什么不是先判断earlySingletonObjects里是否存在singletonObject呢?这个我暂时没找到原因,希望大佬们指点指点。

我们先看下addSingletonFactory方法在哪里被调用的,我们发现只有在doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)方法内调用了addSingletonFactory方法。

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

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   final Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
      mbd.resolvedTargetType = beanType;
   }

   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   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));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      populateBean(beanName, mbd, instanceWrapper);
      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);
      }
   }

   if (earlySingletonExposure) {
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {
         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);
               }
            }
            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 " +
                     "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
            }
         }
      }
   }

   // Register bean as disposable.
   try {
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }

   return exposedObject;
}

因为addSingletonFactory只有一处调用,所以我们核心只看singletonFactory是怎么通过getEarlyBeanReference()方法来的就够了。

// Obtain a reference for early access to the specified bean, typically for the purpose of resolving a circular reference.
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

注意,这个方法的注释上写着该方法用于获取对指定的bean的早期访问的引用,通常用于解析循环引用。所以我们可以推断这个的getObject方法只是返回对应bean的早期访问的引用而已。所以对应的,二级缓存earlySingletonObjects里面也只是存了一个一个bean用于早期访问的引用。

然后回到doCreateBean方法内,我们可以看到真正初始化bean实例的过程在populateBean()和initializeBean()这两个方法上,而会涉及到循环依赖的部分发生在populateBean的方法内。在执行populateBean方法的时候当前beanName对应的实例对象已经存在了,虽然还只是一个用于早期访问的引用,但已经足够了。

然后我们还需要再看一下doCreateBean方法在哪里被调用的,我们一搜发现蛮多的地方有调用的,但是涉及到单例bean的只有一处,就是在上文所提到的getSingleton(String beanName, ObjectFactory<?> singletonFactory)作为singletonFactory的getObject的实现方法中调用的。

而getSingleton()方法中真正能调用doCreateBean方法的的前提条件是一级缓存singletonObjects中不存在对应beanName的singletonObject,否则就直接返回这个singletonObject,而不用再辛辛苦苦走一遍doCreateBean了。

我们现在回到循环依赖的场景内,bean A和bean B相互依赖。

我们假设bean A先初始化,然后此时getSingleton返回的必然是null,需要走createBean方法。

然后在createBean的过程中,先通过addSingletonFactory方法将创建用于早期访问的引用的工厂bean放入到三级缓存singletonFactories内。

然后继续往下走准备populateBean,bean A发现自己有个属性b需要获取到bean B的对象。

此时bean B也尚未被创建,也会走一遍createBean的过程,在createBean的过程中,它调用addSingletonFactory后,然后准备populateBean时发现自己有个属性a需要获取到bean A的对象。

此时走一遍getSingleton方法。发现在singletonObjects里面不存在bean A的singletonObject,然后再从earlySingletonObjects中去试图找到bean A的singletonObject,发现也没有。

然后继续走,发现在singletonFactories中已经存在bean A对应的singletonFactory,此时调用对应的getObject方法获取到bean A的exposedObject(早期引用),将exposedObject放入到的earlySingletonObjects中。

然后bean B在执行populateBean方法中顺利得到了早期引用A’,之后再执行initializeBean方法,此时bean B完成了真正的初始化,最后通过addSingleton方法将bean B的singletonObject放入到singletonObjects中。

此时,bean A还依然是个早期引用,继续往下走,bean A也在执行populateBean方法中顺利得到了实例化后的B,之后再执行initializeBean方法完成了初始化,也通过addSingleton方法将自己的singletonObject放入到singletonObjects中。

到这里,bean A和bean B都顺利完成了实例初始化,也都成功地将自己的instance放入到一级缓存singletonObjects中。

但是此时细心的你,一定会发现,bean A的属性b是最终实例化的B,但是bean B的属性a是早期引用A',最终bean A完成实例化得到的是A。我们可以发现,这A’和A并不一定是同一个对象。

因为在执行initializeBean后,exposedObject得到的是initializeBean方法的返回值,并不一定是之前传入的exposedObject了。如果不能保证A’=A,那就彻底乱套了。

if (earlySingletonExposure) {
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {
         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);
               }
            }
            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 " +
                     "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
            }
         }
      }
   }

我们再回到这块代码上,earlySingletonExposure一定是true,否则也不会调用addSingletonFactory方法。

1、首先判断earlySingletonReference是否为null,这里的earlySingletonReference只能从二级缓存earlySingletonObjects中获取。

不可能是从一级缓存singletonObjects中获取到的,因为前提条件就是singletonObjects不存在对应的对象。

也不可能是从三级缓存singletonFactories获取到的,因为earlySingletonReference是通过getSingleton(beanName, false)获取到的,allowEarlyReference的值为false,就意味着无法从singletonFactories中获取并创建早期引用。

如果不涉及循环引用,那么earlySingletonReference必然是null,因为addSingletonFactory方法只是将对应的beanFactory放入到三级缓存singletonFactories中。那么在实例化过程中一定不会有其他bean通过调用getSingleton(beanName)方法将这个bean的早期引用放入到二级缓存earlySingletonObjects中。

但是如果涉及循环引用,那么这个earlySingletonReference一定不是null,理由同上。

我们上文也讲过,一个bean要想在二级缓存earlySingletonObjects中存在早期引用,一定是因为在这个bean实例化过程中,其他的bean通过getSingleton(beanName)来获取这个bean的引用。

2、如果earlySingletonReference不能null,再判断exposedObject是否等于bean,这里如果exposedObject等于bean,那就意味着initializeBean方法执行后的exposedObject还是之前的bean,经过beanPostProcessor处理的对象没发生变化,这也就意味着A’=A成立,直接用A'代替A。

3、如果exposedObject不等于bean(这意味着经过beanPostProcessor处理的对象发生了变化),然后再判断hasDependentBean方法是否为真,hasDependentBean的方法就是看dependentBeanMap有没有对应的beanName,也就是看当前Bean有没有存在被引用的bean。这时候bean A存在被引用的bean B。

4、最后在判断actualDependentBeans是否为空,其实就是判断removeSingletonIfCreatedForTypeCheckOnly有没有返回false的,其实就是判断那些引用了当前Bean的对象是否都被创建了。只要有一个被创建了,就会爆BeanCurrentlyInCreationException。

我们可以发现解决循环依赖的关键就在于单例bean都是先创建早期引用,然后将对应的beanFactory放入到三级缓存singletonFactories中,先行暴露自己的beanFactory。

这样即便时自己还未完成完成初始化,其他的bean也可以通过三级缓存(singletonFactories)或是二级缓存(earlySingletonObjects)获取到早期引用。第一次通过singletonFactories,第二次就是通过earlySingletonObjects了。

这样就不妨碍其他bean继续实例化。然后只要保证beanPostProcessor方法处理后的对象不发生改变,就可以满足循环依赖的条件。

当然如果在循环依赖中,先加载的bean是通过构造方法注入,那肯定是不行的。

因为createBeanInstance在addSingletonFactory方法之前执行,在执行createBeanInstance的时候,三级缓存singletonFactories并没有生成当前bean的beanFactory,这也就导致了去创建其他bean的时候会拿不到当前bean的引用。

而后加载的bean无论是通过构造器注入还是属性注入还是setter方法注入都没关系,因为此时先加载的bean的用于早期访问的引用已经存在了,后加载的bean可以通过缓存拿到先加载bean的引用,也就无所谓何种注入方式了。

所以要想spring自动解决循环依赖的问题,就必须满足三个前提条件:
1、先注入的bean不能通过构造器注入,否则后加载的bean无法拿到先加载bean的引用。
2、BeanPostProcessor处理过的Bean不能发生变化,否则早期引用会和最终实例化的引用不相等。
3、必须得是单例bean,否则走不了缓存,也就无法拿到对应的引用了。

思路比较跳跃,还请多多海涵。如有不明白或是看法不一致的地方,欢迎大家留言讨论。