什么是循环依赖?
顾名思义,就是假设有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,否则走不了缓存,也就无法拿到对应的引用了。
思路比较跳跃,还请多多海涵。如有不明白或是看法不一致的地方,欢迎大家留言讨论。