【JavaSpring框架是如何解决Bean创建过程中的循环依赖问题的

2023年 7月 31日 74.5k 0

引言

本文主要梳理了Spring框架Bean创建过程中应对循环依赖问题的相关源码。我在手写super-mini-webpack的时候也介绍过解决循环依赖的算法:Map+记忆化搜索。可以猜测这段源码也实现了这个算法,所以在看这段源码的时候,我们可以先找到递归点,再去分析调用栈涉及的那些函数,顺便找出其用到的Map数据结构。

作者:hans774882968以及hans774882968以及hans774882968

本文所用工程

本文CSDN

本文juejin

本文52pojie:www.52pojie.cn/thread-1814…

三级缓存数据结构简介

三级缓存数据结构定义和操作三级缓存的函数都位于:spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java

	/** Cache of singleton objects: bean name to bean instance. */
	private final Map singletonObjects = new ConcurrentHashMap(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	private final Map

    
        
    
    
        
    

A.java和B.java:

// A 和 B 不能都使用 lombok,否则无法打印。这里选择了 B 不使用 lombok
package com.hans.bean_dependency_cycle.hans;

import lombok.Data;

@Data
public class A {
    private B b;

    public String toString(A o) {
        return o.getClass().getName() + "@" +
                Integer.toHexString(System.identityHashCode(o));
    }

}

package com.hans.bean_dependency_cycle.hans;

public class B {
    private A a;

    public A getA() {
        return this.a;
    }

    public void setA(A a) {
        this.a = a;
    }

}

期望输出:

A(b=com.hans.bean_dependency_cycle.hans.B@750e2b97)
com.hans.bean_dependency_cycle.hans.B@750e2b97
com.hans.bean_dependency_cycle.hans.B@750e2b97
A(b=com.hans.bean_dependency_cycle.hans.B@750e2b97)

场景1不需要配置spring.main.allow-circular-references为true也能得到期望输出,TODO:原因未知。

场景2:通过注解+自动装配属性来构造循环引用:以@Controller为例

入口src\main\java\com\hans\bean_dependency_cycle\hans\AnotherEntry.java

package com.hans.bean_dependency_cycle.hans;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class AnotherEntry {
    public static void main(String[] args) {
        ConfigurableApplicationContext cac = SpringApplication.run(AnotherEntry.class, args);
        ControllerA beanA = cac.getBean(ControllerA.class);
        System.out.println(beanA);
        System.out.println(beanA.getCb());
        ControllerB beanB = cac.getBean(ControllerB.class);
        System.out.println(beanB);
        System.out.println(beanB.getCa());
    }
}

根据参考链接1,接下来一定要记得修改application.yml

spring:
  main:
    allow-circular-references: true

否则会报错:

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  controllerA (field private com.hans.bean_dependency_cycle.hans.ControllerB com.hansn_dependency_cycle.hans.ControllerA.cb)
↑     ↓
|  controllerB (field private com.hans.bean_dependency_cycle.hans.ControllerA com.hansn_dependency_cycle.hans.ControllerB.ca)
└─────┘


Action:

Relying upon circular references is discouraged and they are prohibited by default. Up your application to remove the dependency cycle between beans. As a last resort, it me possible to break the cycle automatically by setting spring.main.allow-circular-refees to true.

两个普通的Controller:

// src\main\java\com\hans\bean_dependency_cycle\hans\ControllerA.java
package com.hans.bean_dependency_cycle.hans;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ControllerA {
    @Autowired
    private ControllerB cb;

    public ControllerB getCb() {
        return cb;
    }

    @RequestMapping("/controllerA")
    public String index() {
        return "hello controllerA!";
    }
}

// src\main\java\com\hans\bean_dependency_cycle\hans\ControllerB.java
package com.hans.bean_dependency_cycle.hans;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ControllerB {
    @Autowired
    private ControllerA ca;

    public ControllerA getCa() {
        return ca;
    }

    @RequestMapping("/controllerB")
    public String index() {
        return "hello controllerB!";
    }
}

期望输出:

com.hans.bean_dependency_cycle.hans.ControllerA@39f82681
com.hans.bean_dependency_cycle.hans.ControllerB@4bd9e7fd
com.hans.bean_dependency_cycle.hans.ControllerB@4bd9e7fd
com.hans.bean_dependency_cycle.hans.ControllerA@39f82681

脉络

根据参考链接2,有一个经验:“do”开头的方法名是真正含有大量逻辑的方法。参考链接2Java之父精选的脉络函数如下:

  • getBean
  • doGetBean
  • createBean
  • doCreateBean
  • createBeanInstance
  • populateBean

场景1到递归点为止的调用链:preInstantiateSingletons > getBean > doGetBean > getSingleton函数有多个,其中调用了beforeSingletonCreation的函数调用singletonFactory.getObject()时才真正调用了createBean > createBean > doCreateBean > createBeanInstance, populateBean 都在 doCreateBean 的实现里 > populateBean调用了applyPropertyValues > resolveValueIfNecessary > resolveReference > getBean

场景2的调用链到populateBean开始和场景1的调用链岔开,两个场景的差异放在后文《Controller和普通Bean解决循环依赖过程的相同点与不同点》分析。

场景1递归到A -> B -> A时的调用链:getBean > doGetBean > 未调用beforeSingletonCreation的getSingleton,操作第2级缓存后离开

操作三级缓存的函数都位于https://github.com/spring-projects/spring-framework/blob/502997d8e986dcfde1f49b2b2f443a32b5488b13/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java

  • 放入第3级缓存的函数:doCreateBean调用的addSingletonFactory
  • 放入第2级缓存的函数:首先要知道getSingletonDefaultSingletonBeanRegistry.java里本质上的实现有两个,一个public Object getSingleton(String beanName, ObjectFactory singletonFactory)调用了beforeSingletonCreation并间接调用了createBean;另一个protected Object getSingleton(String beanName, boolean allowEarlyReference)则是操作了第2级缓存。
  • 放入第1级缓存的函数:addSingleton。在间接调用了createBean函数的getSingleton处调用。
  • 场景1的执行过程

    真正意义上的入口:spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java的beanFactory.preInstantiateSingletons();。这里的beanFactory就有singletonObjects那3级缓存的对象。于是跳到https://github.com/spring-projects/spring-framework/blob/bbde68c49e66c3c531920cb80a55742262507be7/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

    	@Override
    	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 beanNames = new ArrayList(this.beanDefinitionNames);
    
            // 触发所有非延迟加载的(non-lazy)单例 bean 的初始化
    		// Trigger initialization of all non-lazy singleton beans...
    		for (String beanName : beanNames) {
    			// 假如先遍历 A 再遍历 B 那么遍历到 B 的时候,因为循环引用解决的关系,B 已经放到了第1级缓存,所以 doGetBean 的 getSingleton 可以直接从第1级缓存取到值,不用再走一遍 createBean 方法
                // 合并父类 BeanDefinition
    			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                // 非抽象、是单例、非懒加载
    			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                    // 如果实现了 FactoryBean 接口则是 FactoryBean
    				if (isFactoryBean(beanName)) {
    					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); // 比如:FACTORY_BEAN_PREFIX + beanName = "&A"
    					if (bean instanceof SmartFactoryBean smartFactoryBean && smartFactoryBean.isEagerInit()) {
    						getBean(beanName);
    					}
    				}
    				else {
                        // 不是 FactoryBean,只是普通 Bean,则走这个分支
    					getBean(beanName);
    				}
    			}
    		}
    
            // 触发所有 SmartInitializingSingleton 的后初始化回调
    		// Trigger post-initialization callback for all applicable beans...
    		for (String beanName : beanNames) {
    			Object singletonInstance = getSingleton(beanName);
    			if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
    				StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
    						.tag("beanName", beanName);
    				smartSingleton.afterSingletonsInstantiated();
    				smartInitialize.end();
    			}
    		}
    	}
    

    顺便看下isFactoryBean的实现https://github.com/spring-projects/spring-framework/blob/4786e2bf53a3f882c10e25d7ff79a18ff47b5e51/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

    	@Override
    	public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
    		String beanName = transformedBeanName(name);
    		Object beanInstance = getSingleton(beanName, false);
    		if (beanInstance != null) {
    			return (beanInstance instanceof FactoryBean);
    		}
    		// No singleton instance found -> check bean definition.
    		if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory cbf) {
    			// No bean definition found in this factory -> delegate to parent.
    			return cbf.isFactoryBean(name);
    		}
    		return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
    	}
    

    getBeanisFactoryBean都位于https://github.com/spring-projects/spring-framework/blob/4786e2bf53a3f882c10e25d7ff79a18ff47b5e51/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.javagetBean只有1行

    	@Override
    	public Object getBean(String name) throws BeansException {
    		return doGetBean(name, null, null, false);
    	}
    

    doGetBeangetBean, isFactoryBean都在AbstractBeanFactory.java

    	/**
    	 * Return an instance, which may be shared or independent, of the specified bean.
    	 * @param name the name of the bean to retrieve
    	 * @param requiredType the required type of the bean to retrieve
    	 * @param args arguments to use when creating a bean instance using explicit arguments
    	 * (only applied when creating a new instance as opposed to retrieving an existing one)
    	 * @param typeCheckOnly whether the instance is obtained for a type check,
    	 * not for actual use
    	 * @return an instance of the bean
    	 * @throws BeansException if the bean could not be created
    	 */
    	@SuppressWarnings("unchecked")
    	protected  T doGetBean(
    			String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    			throws BeansException {
    
    		String beanName = transformedBeanName(name);
    		Object beanInstance;
    
            // 提前检查单例缓存中是否有手动注册的单例对象,跟循环依赖有关。如果是初次进这里,比如 controllerA 初次进这个方法,肯定是拿不到值的,就会是 null
    		// 对于最简单的循环依赖,controllerA -> controllerB -> controllerA 之后,需要进入 getSingleton 了,这里的逻辑就是要从第3级缓存里拿到工厂函数,调用后得到 controllerA 半成品,从而可以直接 return
    		// 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 + "'");
    				}
    			}
    			beanInstance = 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 abf) {
    					return abf.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);
    			}
    
    			StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
    					.tag("beanName", name);
    			try {
    				if (requiredType != null) {
    					beanCreation.tag("beanType", requiredType::toString);
    				}
    				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()) {
    					// 返回 beanName 的原始单例对象。如果尚未注册,则使用 singletonFactory 创建并注册一个对象
    					sharedInstance = getSingleton(beanName, () -> {
    						try {
    							// 为给定的合并后的 BeanDefinition 和参数创建一个 bean 实例
    							// createBean 真实执行时机是调用了 beforeSingletonCreation 方法的 getSingleton 方法执行 singletonObject = singletonFactory.getObject() 时
    							// 首次运行到 beanName = "controllerA" 时 args = null
    							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.
    							// 显式地从单例缓存中删除bean实例:因为这个实例可能是由创建过程急切地放在那里的,放在那里的目的是允许循环引用解析。
    							// 还要删除所有被这个bean临时引用的所有bean。如果找到相应的一次性bean实例,则委托给 destroyBean
    							destroySingleton(beanName);
    							throw ex;
    						}
    					});
    					beanInstance = 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);
    					}
    					beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    				}
    
    				else {
    					String scopeName = mbd.getScope();
    					if (!StringUtils.hasLength(scopeName)) {
    						throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
    					}
    					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);
    							}
    						});
    						beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
    					}
    					catch (IllegalStateException ex) {
    						throw new ScopeNotActiveException(beanName, scopeName, ex);
    					}
    				}
    			}
    			catch (BeansException ex) {
    				beanCreation.tag("exception", ex.getClass().toString());
    				beanCreation.tag("message", String.valueOf(ex.getMessage()));
    				cleanupAfterBeanCreationFailure(beanName);
    				throw ex;
    			}
    			finally {
    				beanCreation.end();
    			}
    		}
    
    		return adaptBeanInstance(name, beanInstance, requiredType);
    	}
    

    我们先只关注createBean,所以需要关注getSingleton。注意:

    getSingleton的函数在DefaultSingletonBeanRegistry.java里本质上的实现有两个,一个调用了beforeSingletonCreation并间接调用了createBean;另一个则是操作了第2级缓存。

    所以目前我们需要关注的是调用了beforeSingletonCreationgetSingleton方法。路径:https://github.com/spring-projects/spring-framework/blob/502997d8e986dcfde1f49b2b2f443a32b5488b13/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java

    	/**
    	 * Return the (raw) singleton object registered under the given name,
    	 * creating and registering a new one if none registered yet.
    	 * @param beanName the name of the bean
    	 * @param singletonFactory the ObjectFactory to lazily create the singleton
    	 * with, if necessary
    	 * @return the registered singleton object
    	 */
    	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 + "'");
    				}
    				// 创建单例前的回调,默认实现为:将单例注册为当前正在创建中,实现只有3行,可以看下。
    				beforeSingletonCreation(beanName);
    				// flag 表示是否生成了新的单例对象
    				boolean newSingleton = false;
    				// flag 表示是否有抑制异常的记录,true表示没有
    				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
    				if (recordSuppressedExceptions) {
    					// 若没有抑制异常记录,则对抑制异常列表进行初始化
    					this.suppressedExceptions = new LinkedHashSet();
    				}
    				try {
    					// 从单例工厂获取对象。注意 singletonFactory 是本方法第二个参数,之前也介绍了
    					// ObjectFactory 对象通过调 getObject 来正式执行函数,所以 createBean 在此时才真正执行
    					singletonObject = singletonFactory.getObject();
    					// 获取后,就已经生成了新的单例对象,标记为 true
    					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) {
    					// 操作第1级缓存
    					addSingleton(beanName, singletonObject);
    				}
    			}
    			return singletonObject;
    		}
    	}
    

    在调用singletonObject = singletonFactory.getObject();以间接调用createBean后,会调用addSingleton,将bean加入第1级缓存,这标志着bean变为成品。接下来我们看下addSingleton的代码,它和getSingleton定义于同一个文件。

    	/**
    	 * Add the given singleton object to the singleton cache of this factory.
    	 * 

    To be called for eager registration of singletons. * @param beanName the name of the bean * @param singletonObject the singleton object */ protected void addSingleton(String beanName, Object singletonObject) { // addSingleton 在调用了 createBean 的 getSingleton 方法中被调用,标志着 bean 变为成品对象 synchronized (this.singletonObjects) { // 第1级缓存添加,第2、3级缓存移除 this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); // 添加到已注册的单例集合。 registeredSingletons 为 Set this.registeredSingletons.add(beanName); } }

    接下来看createBeanhttps://github.com/spring-projects/spring-framework/blob/4786e2bf53a3f882c10e25d7ff79a18ff47b5e51/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

    	/**
    	 * Central method of this class: creates a bean instance,
    	 * populates the bean instance, applies post-processors, etc.
    	 * @see #doCreateBean
    	 */
    	@Override
    	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    		// 首次看源码,直接看 doCreateBean 调用处
    		if (logger.isTraceEnabled()) {
    			logger.trace("Creating instance of bean '" + beanName + "'");
    		}
    		RootBeanDefinition mbdToUse = mbd;
    
    		// Make sure bean class is actually resolved at this point, and
    		// clone the bean definition in case of a dynamically resolved Class
    		// which cannot be stored in the shared merged bean definition.
    		Class resolvedClass = resolveBeanClass(mbd, beanName);
    		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    			mbdToUse = new RootBeanDefinition(mbd);
    			mbdToUse.setBeanClass(resolvedClass);
    		}
    
    		// Prepare method overrides.
    		try {
    			mbdToUse.prepareMethodOverrides();
    		}
    		catch (BeanDefinitionValidationException ex) {
    			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
    					beanName, "Validation of method overrides failed", ex);
    		}
    
    		try {
    			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
    			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目前唯一值得关注的点就是调用了doCreateBeandoCreateBean做了几件值得本文关注的事:

    • 调用了createBeanInstance完成bean的实例化。
    • 调用了addSingletonFactory,即加入了第3级缓存。
    • 调用了populateBean完成bean的属性赋值操作。

    doCreateBeancreateBean都定义在https://github.com/spring-projects/spring-framework/blob/4786e2bf53a3f882c10e25d7ff79a18ff47b5e51/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

    	/**
    	 * Actually create the specified bean. Pre-creation processing has already happened
    	 * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
    	 * 

    Differentiates between default bean instantiation, use of a * factory method, and autowiring a constructor. * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param args explicit arguments to use for constructor or factory method invocation * @return a new instance of the bean * @throws BeanCreationException if the bean could not be created * @see #instantiateBean * @see #instantiateUsingFactoryMethod * @see #autowireConstructor */ protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. // instanceWrapper 持有创建出的 bean 对象 BeanWrapper instanceWrapper = null; // 获取 factoryBean 实例缓存 if (mbd.isSingleton()) { // 如果是单例对象,从 factoryBean 实例缓存中移除当前 bean 的信息 // 首次 controllerA 进来会进行移除操作,并且会调用 createBeanInstance instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // 没有就创建实例 if (instanceWrapper == null) { // 根据执行 bean 使用对应的策略创建新的工厂实例,如:工厂方法、构造函数主动注入、简单初始化 // 第一次读源码时不需要点进去看 createBeanInstance 。下一个主干方法 populateBean 是在本函数下文调用的 instanceWrapper = createBeanInstance(beanName, mbd, args); } // 从包装类中获取原始 bean 。首次执行 controllerA 的时候, bean 就是普通的 controllerA 对象 ControllerA@100{cb=null} Object bean = instanceWrapper.getWrappedInstance(); // 获取具体 bean 对象的 Class 属性 Class beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { // 不等于 NullBean 类型时就修改目标类型 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.markAsPostProcessed(); } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. // 判断当前 bean 是否需要提前曝光,条件为:是单例 && 允许循环依赖 spring.main.allow-circular-references 配置为 true && 当前 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"); } // 为避免后期循环依赖,可以在 bean 初始化完成前将创建实例的 ObjectFactory 加入工厂 // 注意,这个方法会操作3级缓存的数据结构,尤其是第3级缓存。在 controllerA -> controllerB -> controllerA 的时候未调用 createBean 的 getSingleton 方法会真正调用这个匿名函数,从而调用 getEarlyBeanReference 进而操作第2级缓存 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. // controllerA 首次执行到这里时,exposedObject = ControllerA@100{cb=null} Object exposedObject = bean; try { // populateBean 是主干方法,给刚刚实例化的 bean (半成品)填充属性 populateBean(beanName, mbd, instanceWrapper); // controllerA -> controllerB -> controllerA 之后,getSingleton 返回 controllerA 后回到这里, controllerB 的 ca 属性就有值了 // 随后递归返回到这句话且调用栈只有 controllerA 的时候,发现两者都有值了 exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) { throw bce; } else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), 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 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 " + "'getBeanNamesForType' 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; }

    createBeanInstance的细节与本文主题无关,不关注。接下来我们看下addSingletonFactory的实现。addSingletonFactory位于https://github.com/spring-projects/spring-framework/blob/502997d8e986dcfde1f49b2b2f443a32b5488b13/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java,主要动作是操作第3级缓存。

    	/**
    	 * Add the given singleton factory for building the specified singleton
    	 * if necessary.
    	 * 

    To be called for eager registration of singletons, e.g. to be able to * resolve circular references. * @param beanName the name of the bean * @param singletonFactory the factory for the singleton object */ protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { // controllerA 首次执行到这里,第一级缓存肯定是查不到的 if (!this.singletonObjects.containsKey(beanName)) { // 第3级缓存放入。再回顾一下, singletonFactory存的是 beanName 到一个延迟执行的函数的映射 // controllerA 首次执行到这里的时候, singletonFactory = () -> getEarlyBeanReference(beanName, mbd, bean) this.singletonFactories.put(beanName, singletonFactory); // 从早期单例对象的高速缓存(即第2级缓存)移除当前 beanName 对应的缓存对象 this.earlySingletonObjects.remove(beanName); // 添加到已注册的单例集合里,和三级缓存无关。值得注意的是, A 首次加入三级缓存时,就是首次加入已注册的单例集合 this.registeredSingletons.add(beanName); } } }

    接下来关注位于https://github.com/spring-projects/spring-framework/blob/4786e2bf53a3f882c10e25d7ff79a18ff47b5e51/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.javapopulateBeanpopulateBean方法有一个功能是给bean的属性赋值,包含了递归点。在创建Bean的源码中,递归点指的是递归调用getBean方法。

    	/**
    	 * Populate the bean instance in the given BeanWrapper with the property values
    	 * from the bean definition.
    	 * @param beanName the name of the bean
    	 * @param mbd the bean definition for the bean
    	 * @param bw the BeanWrapper with bean instance
    	 */
    	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;
    			}
    		}
    
    		if (bw.getWrappedClass().isRecord()) {
    			if (mbd.hasPropertyValues()) {
    				throw new BeanCreationException(
    						mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
    			}
    			else {
    				// Skip property population phase for records since they are immutable.
    				return;
    			}
    		}
    
    		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    		// state of the bean before properties are set. This can be used, for example,
    		// to support styles of field injection.
    		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
    				if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    					return;
    				}
    			}
    		}
    
    		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    
    		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    			// Add property values based on autowire by name if applicable.
    			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
    				autowireByName(beanName, mbd, bw, newPvs);
    			}
    			// Add property values based on autowire by type if applicable.
    			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
    				autowireByType(beanName, mbd, bw, newPvs);
    			}
    			pvs = newPvs;
    		}
    		if (hasInstantiationAwareBeanPostProcessors()) {
    			if (pvs == null) {
    				pvs = mbd.getPropertyValues();
    			}
    			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
    				// 对于 Controller Bean 自动装配属性产生循环依赖的场景,遍历到 AutowiredAnnotationBeanPostProcessor 时,这句话包含递归点
    				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    				if (pvsToUse == null) {
    					return;
    				}
    				pvs = pvsToUse;
    			}
    		}
    
    		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    		if (needsDepCheck) {
    			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    			checkDependencies(beanName, mbd, filteredPds, pvs);
    		}
    
    		if (pvs != null) {
    			// 对于普通 Bean 的场景,这句话包含递归点
    			applyPropertyValues(beanName, mbd, bw, pvs);
    		}
    	}
    

    applyPropertyValues也位于https://github.com/spring-projects/spring-framework/blob/4786e2bf53a3f882c10e25d7ff79a18ff47b5e51/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java,主要功能为完成bean初始化。其中,Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue)包含了递归点,通过动调可以验证bw.setPropertyValues(new MutablePropertyValues(deepCopy))真正完成了属性赋值工作。

    	/**
    	 * Apply the given property values, resolving any runtime references
    	 * to other beans in this bean factory. Must use deep copy, so we
    	 * don't permanently modify this property.
    	 * @param beanName the bean name passed for better exception information
    	 * @param mbd the merged bean definition
    	 * @param bw the BeanWrapper wrapping the target object
    	 * @param pvs the new property values
    	 */
    	protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    		// applyPropertyValues 是真正完成赋值操作的函数
    		// 如果 pvs 没有 PropertyValue,就直接结束
    		if (pvs.isEmpty()) {
    			return;
    		}
    
    		MutablePropertyValues mpvs = null;
    		List original;
    
    		if (pvs instanceof MutablePropertyValues _mpvs) {
    			mpvs = _mpvs;
    			if (mpvs.isConverted()) {
    				// Shortcut: use the pre-converted values as-is.
    				try {
    					bw.setPropertyValues(mpvs);
    					return;
    				}
    				catch (BeansException ex) {
    					throw new BeanCreationException(
    							mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    				}
    			}
    			// 获取 mpvs 的 PropertyValue 列表
    			original = mpvs.getPropertyValueList();
    		}
    		else {
    			// 获取 pvs 的 PropertyValue 对象数组并转为列表
    			original = Arrays.asList(pvs.getPropertyValues());
    		}
    
    		// 用户自定义的类型转换器,默认转换器为 bean 的包装类对象
    		TypeConverter converter = getCustomTypeConverter();
    		if (converter == null) {
    			converter = bw;
    		}
    		BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
    
    		// Create a deep copy, resolving any references for values.
    		List deepCopy = new ArrayList(original.size());
    		// resolveNecessary flag 含义为是否还需要解析
    		boolean resolveNecessary = false;
    		for (PropertyValue pv : original) {
    			// 属性已解析过则加入 deepCopy
    			if (pv.isConverted()) {
    				deepCopy.add(pv);
    			}
    			else {
    				String propertyName = pv.getName();
    				// 获取未经类型转换的值
    				Object originalValue = pv.getValue();
    				if (originalValue == AutowiredPropertyMarker.INSTANCE) {
    					Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
    					// 如果 setter 方法为空
    					if (writeMethod == null) {
    						// 异常:自动装配标记属性没有写方法
    						throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
    					}
    					originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
    				}
    				// 交由 valueResolver 根据 pv 解析出 originalValue 所封装的对象。注意:这个函数包含递归点
    				Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
    				Object convertedValue = resolvedValue;
    				// flag 含义为是否可转换: propertyName 是 bw 中的可写属性 && propertyName 不是索引属性或嵌套属性
    				boolean convertible = bw.isWritableProperty(propertyName) &&
    						!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
    				if (convertible) {
    					// 可转换则将 resolvedValue 转换为指定的目标属性对象
    					convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
    				}
    				// Possibly store converted value in merged bean definition,
    				// in order to avoid re-conversion for every created bean instance.
    				if (resolvedValue == originalValue) {
    					if (convertible) {
    						pv.setConvertedValue(convertedValue);
    					}
    					deepCopy.add(pv);
    				}
    				else if (convertible && originalValue instanceof TypedStringValue typedStringValue &&
    						!typedStringValue.isDynamic() &&
    						!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
    					pv.setConvertedValue(convertedValue);
    					deepCopy.add(pv);
    				}
    				else {
    					resolveNecessary = true;
    					deepCopy.add(new PropertyValue(pv, convertedValue));
    				}
    			}
    		}
    		if (mpvs != null && !resolveNecessary) {
    			mpvs.setConverted();
    		}
    
    		// Set our (possibly massaged) deep copy.
    		try {
    			// 完成属性赋值工作。咱们做个简单的实验,动调执行此句前后各点击调用栈看一次 populateBean 调用处的下一句的 exposedObject 或者 bean 变量,这就证实了 bean 的属性赋值确实是在这句话完成的
    			bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    		}
    		catch (BeansException ex) {
    			throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
    		}
    	}
    

    resolveValueIfNecessary位于https://github.com/spring-projects/spring-framework/blob/30d6ec3398ce41add7bc44d360b8fb86ac0264b1/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java。其实现也很长,但目前只需要关注return resolveReference(argName, ref),因为resolveReference包含递归点。

    	/**
    	 * Given a PropertyValue, return a value, resolving any references to other
    	 * beans in the factory if necessary. The value could be:
    	 * 
  • A BeanDefinition, which leads to the creation of a corresponding * new bean instance. Singleton flags and names of such "inner beans" * are always ignored: Inner beans are anonymous prototypes. *
  • A RuntimeBeanReference, which must be resolved. *
  • A ManagedList. This is a special collection that may contain * RuntimeBeanReferences or Collections that will need to be resolved. *
  • A ManagedSet. May also contain RuntimeBeanReferences or * Collections that will need to be resolved. *
  • A ManagedMap. In this case the value may be a RuntimeBeanReference * or Collection that will need to be resolved. *
  • An ordinary object or {@code null}, in which case it's left alone. * @param argName the name of the argument that the value is defined for * @param value the value object to resolve * @return the resolved object */ @Nullable public Object resolveValueIfNecessary(Object argName, @Nullable Object value) { // We must check each value to see whether it requires a runtime reference // to another bean to be resolved. // RuntimeBeanReference:当属性值对象是工厂中另一个 bean 的引用时,使用不可变的占位符类,在运行时进行解析 if (value instanceof RuntimeBeanReference ref) { // 解析出对应 ref 所封装的 Bean 的元信息的 Bean 对象。Bean 的元信息:Bean 名,Bean类型。注意,这个函数里包含递归点 return resolveReference(argName, ref); } else if (value instanceof RuntimeBeanNameReference ref) { String refName = ref.getBeanName(); refName = String.valueOf(doEvaluate(refName)); if (!this.beanFactory.containsBean(refName)) { throw new BeanDefinitionStoreException( "Invalid bean name '" + refName + "' in bean reference for " + argName); } return refName; } else if (value instanceof BeanDefinitionHolder bdHolder) { // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases. return resolveInnerBean(bdHolder.getBeanName(), bdHolder.getBeanDefinition(), (name, mbd) -> resolveInnerBeanValue(argName, name, mbd)); } else if (value instanceof BeanDefinition bd) { return resolveInnerBean(null, bd, (name, mbd) -> resolveInnerBeanValue(argName, name, mbd)); } else if (value instanceof DependencyDescriptor dependencyDescriptor) { Set autowiredBeanNames = new LinkedHashSet(2); Object result = this.beanFactory.resolveDependency( dependencyDescriptor, this.beanName, autowiredBeanNames, this.typeConverter); for (String autowiredBeanName : autowiredBeanNames) { if (this.beanFactory.containsBean(autowiredBeanName)) { this.beanFactory.registerDependentBean(autowiredBeanName, this.beanName); } } return result; } else if (value instanceof ManagedArray managedArray) { // May need to resolve contained runtime references. Class elementType = managedArray.resolvedElementType; if (elementType == null) { String elementTypeName = managedArray.getElementTypeName(); if (StringUtils.hasText(elementTypeName)) { try { elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader()); managedArray.resolvedElementType = elementType; } catch (Throwable ex) { // Improve the message by showing the context. throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, ex); } } else { elementType = Object.class; } } return resolveManagedArray(argName, (List) value, elementType); } else if (value instanceof ManagedList managedList) { // May need to resolve contained runtime references. return resolveManagedList(argName, managedList); } else if (value instanceof ManagedSet managedSet) { // May need to resolve contained runtime references. return resolveManagedSet(argName, managedSet); } else if (value instanceof ManagedMap managedMap) { // May need to resolve contained runtime references. return resolveManagedMap(argName, managedMap); } else if (value instanceof ManagedProperties original) { // Properties original = managedProperties; Properties copy = new Properties(); original.forEach((propKey, propValue) -> { if (propKey instanceof TypedStringValue typedStringValue) { propKey = evaluate(typedStringValue); } if (propValue instanceof TypedStringValue typedStringValue) { propValue = evaluate(typedStringValue); } if (propKey == null || propValue == null) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting Properties key/value pair for " + argName + ": resolved to null"); } copy.put(propKey, propValue); }); return copy; } else if (value instanceof TypedStringValue typedStringValue) { // Convert value to target type here. Object valueObject = evaluate(typedStringValue); try { Class resolvedTargetType = resolveTargetType(typedStringValue); if (resolvedTargetType != null) { return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); } else { return valueObject; } } catch (Throwable ex) { // Improve the message by showing the context. throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, ex); } } else if (value instanceof NullBean) { return null; } else { return evaluate(value); } }
  • resolveReferenceresolveValueIfNecessary都位于https://github.com/spring-projects/spring-framework/blob/30d6ec3398ce41add7bc44d360b8fb86ac0264b1/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java。其实现也很长,但目前只需要关注bean = this.beanFactory.getBean(resolvedName),因为这就是递归点。

    	/**
    	 * Resolve a reference to another bean in the factory.
    	 */
    	@Nullable
    	private Object resolveReference(Object argName, RuntimeBeanReference ref) {
    		try {
    			Object bean;
    			Class beanType = ref.getBeanType();
    			// 如果引用来自父工厂
    			if (ref.isToParent()) {
    				// 获取父工厂
    				BeanFactory parent = this.beanFactory.getParentBeanFactory();
    				if (parent == null) {
    					// 没有父工厂则报错:在父工厂中无法解析对 Bean 的引用,因为父工厂就不存在
    					throw new BeanCreationException(
    							this.beanDefinition.getResourceDescription(), this.beanName,
    							"Cannot resolve reference to bean " + ref +
    									" in parent factory: no parent factory available");
    				}
    				if (beanType != null) {
    					bean = parent.getBean(beanType);
    				}
    				else {
    					bean = parent.getBean(String.valueOf(doEvaluate(ref.getBeanName())));
    				}
    			}
    			else {
    				String resolvedName;
    				if (beanType != null) {
    					// 解析与 beanType 唯一匹配的 bean 实例,包括其 bean 名
    					NamedBeanHolder namedBean = this.beanFactory.resolveNamedBean(beanType);
    					// 让 bean 引用 namedBean 所封装的 bean 对象
    					bean = namedBean.getBeanInstance();
    					resolvedName = namedBean.getBeanName();
    				}
    				else {
    					resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
    					// 获取 ref 所包装的 Bean 名对应的 Bean 对象
    					// 注意,这就是递归点了
    					bean = this.beanFactory.getBean(resolvedName);
    				}
    				// 注册依赖关系到 Bean 工厂
    				this.beanFactory.registerDependentBean(resolvedName, this.beanName);
    			}
    			if (bean instanceof NullBean) {
    				bean = null;
    			}
    			return bean;
    		}
    		catch (BeansException ex) {
    			throw new BeanCreationException(
    					this.beanDefinition.getResourceDescription(), this.beanName,
    					"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
    		}
    	}
    

    B创建过程调用栈是完全一样的,接下来我们假设现在走到了A -> B -> A,回到了doGetBeanObject sharedInstance = getSingleton(beanName);处。此时我们需要关注其实现了:

    	/**
    	 * Return the (raw) singleton object registered under the given name.
    	 * 

    Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */ @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { // Quick check for existing instance without full singleton lock // 该函数主要是调用放入第3级缓存的 getEarlyBeanReference 并放入第2级缓存 // 首先从第1级缓存获取 bean Object singletonObject = this.singletonObjects.get(beanName); // 第1级缓存没有,并且已标记为创建中 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 从第2级缓存获取 bean.因为controllerA -> controllerB -> controllerA 的时候是创建中的 bean,只放到了第3级缓存,所以是查不到的 singletonObject = this.earlySingletonObjects.get(beanName); // controllerA -> controllerB -> controllerA 的时候进来, allowEarlyReference 肯定是 true if (singletonObject == null && allowEarlyReference) { synchronized (this.singletonObjects) { // Consistent creation of early reference within full singleton lock // 这段做二次确认的代码让我联想到线程安全的单例模式的写法 // 从第1级缓存取 singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 从第2级缓存取 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) { // 从第3级缓存取。如果是 controllerA 初次进来,因为 not in creation 所以不会进这里,就算进了这里,因为第3级缓存取不到所以还是会直接 return。如果是 controllerA -> controllerB -> controllerA 则会操作第2级缓存 ObjectFactory singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 回顾一下,DefaultSingletonBeanRegistry.java 的 addSingletonFactory 函数在操作第3级缓存的时候,放入的匿名函数就是: // singletonFactory = () -> getEarlyBeanReference(beanName, mbd, bean) 所以 getEarlyBeanReference 返回值会在此被放入第2级缓存 singletonObject = singletonFactory.getObject(); // 为什么是放第2级缓存?因为 getBean 的递归还没返回 // 放入第2级缓存后,三级缓存的就可以移除了 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } } } return singletonObject; }

    A -> B -> A的递归返回后,A, B两个单例bean都已经是成品,beanName遍历到B的时候,进入getSingleton就能命中第1级缓存了,不用再走一遍createBean方法。

    		for (String beanName : beanNames) {
    			// 假如先遍历 A 再遍历 B 那么遍历到 B 的时候,因为循环引用解决的关系,B 已经放到了第1级缓存,所以 doGetBean 的 getSingleton 可以直接从第1级缓存取到值,不用再走一遍 createBean 方法
                // 合并父类 BeanDefinition
    			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                // 非抽象、是单例、非懒加载
    			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                    // 如果实现了 FactoryBean 接口则是 FactoryBean
    				if (isFactoryBean(beanName)) {
    					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); // 比如:FACTORY_BEAN_PREFIX + beanName = "&A"
    					if (bean instanceof SmartFactoryBean smartFactoryBean && smartFactoryBean.isEagerInit()) {
    						getBean(beanName);
    					}
    				}
    				else {
                        // 不是 FactoryBean,只是普通 Bean,则走这个分支
    					getBean(beanName);
    				}
    			}
    		}
    

    至此,场景1的递归点和三级缓存的操作时机都已经清楚了。

    @Controller+自动装配属性和普通Bean解决循环依赖过程的相同点与不同点

    场景2的Controller使用了@Autowired注解来构造循环依赖。动调可知,这个场景并不是在populateBeanapplyPropertyValues(beanName, mbd, bw, pvs);完成修改的,而是在populateBean的:

    			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
    				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
    				if (pvsToUse == null) {
    					return;
    				}
    				pvs = pvsToUse;
    			}
    

    这个循环里完成属性赋值的。动调发现getBeanPostProcessorCache().instantiationAware有一个元素是AutowiredAnnotationBeanPostProcessor@133(所有元素分别是ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@129, InfrastructureAdvisorAutoProxyCreator@130, PersistenceExceptionTranslationPostProcessor@131, CommonAnnotationBeanPostProcessor@132, AutowiredAnnotationBeanPostProcessor@133),遍历到这个元素时执行的操作完成了自动装配属性的赋值。那我们跟进去看下。

    AutowiredAnnotationBeanPostProcessor.postProcessProperties位于https://github.com/spring-projects/spring-framework/blob/6183f0684684912802021556dce916ba26228c26/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

    	@Override
    	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    		try {
    			metadata.inject(bean, beanName, pvs);
    		}
    		catch (BeanCreationException ex) {
    			throw ex;
    		}
    		catch (Throwable ex) {
    			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    		}
    		return pvs;
    	}
    

    显然是在metadata.inject处完成自动装配的。InjectionMetadata.inject位于https://github.com/spring-projects/spring-framework/blob/2f33e77ab49f136d83b6ebf5eeb72d200fe23c0b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java

    	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    		Collection checkedElements = this.checkedElements;
    		Collection elementsToIterate =
    				(checkedElements != null ? checkedElements : this.injectedElements);
    		if (!elementsToIterate.isEmpty()) {
    			for (InjectedElement element : elementsToIterate) {
    				element.inject(target, beanName, pvs);
    			}
    		}
    	}
    

    element.inject最终跳入的是https://github.com/spring-projects/spring-framework/blob/6183f0684684912802021556dce916ba26228c26/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.javaprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws ThrowableAutowiredFieldElement, AutowiredMethodElement都有inject方法,显然这个case里我们调用的是AutowiredFieldElementinject方法。

    		@Override
    		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    			Field field = (Field) this.member;
    			Object value;
    			if (this.cached) {
    				try {
    					value = resolveCachedArgument(beanName, this.cachedFieldValue);
    				}
    				catch (BeansException ex) {
    					// Unexpected target bean mismatch for cached argument -> re-resolve
    					this.cached = false;
    					logger.debug("Failed to resolve cached argument", ex);
    					value = resolveFieldValue(field, bean, beanName);
    				}
    			}
    			else {
    				value = resolveFieldValue(field, bean, beanName);
    			}
    			if (value != null) {
    				ReflectionUtils.makeAccessible(field);
    				field.set(bean, value);
    			}
    		}
    

    显然field.set(bean, value);最终完成了属性的自动装配。值得注意的是,动调看到resolveFieldValue获取到的cb是已经装配好的,这里一定存在递归调用。我们用一个简单的动态调试技巧来找到递归点:在执行到value = resolveFieldValue(field, bean, beanName)时,给doGetBean函数下一个临时的断点。得到的调用栈如下:

  • AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement.inject()
  • AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement.resolveFieldValue()value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
  • DefaultListableBeanFactory.javaresolveDependency方法的result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
  • DefaultListableBeanFactory.javadoResolveDependency方法的instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
  • https://github.com/spring-projects/spring-framework/blob/f1fe16e3cda66b164f77489f82287116477197bc/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.javaresolveCandidate方法的return beanFactory.getBean(beanName);,这就是递归点了,beanName = controllerB
  • 总而言之,Controller的bean自动装配属性的场景和普通的bean的递归点不一样,但对三级缓存的操作逻辑是完全一致的。谜底已揭晓~

    一些扩展结论

    【1】为什么Spring不能解决构造器的循环依赖?

    doCreateBean调用createBeanInstance时,一二三级缓存都没有Bean的相关信息,在实例化之后才调用addSingletonFactory放入第3级缓存中,因此当getBean的时候缓存不会命中,所以会抛出循环依赖的异常。

    【2】为什么多实例Bean不能解决循环依赖?

    多实例Bean是每次创建都会调用doGetBean方法,mbd.isSingleton()是false,不走sharedInstance = getSingleton(beanName, () -> {这个分支,所以也不会使用三级缓存,不能解决循环依赖。

    总结

  • 根据常识猜测Spring创建Bean过程解决循环依赖的算法也是Map+记忆化搜索。所以我们可以先找到递归点,再去分析调用栈涉及的那些函数,顺便找出其用到的Map数据结构。
  • 在不了解Spring框架的情况下可以用一个动态调试技巧快速找到递归点:在执行到某条顺序靠后的语句时,给顺序靠前的语句下一个断点,若下断成功,则说明找到了递归点。剩下的工作就是关注调用栈涉及的函数。
  • 参考资料

  • 痛快!SpringBoot终于禁掉了循环依赖!juejin.cn/post/709679…
  • www.bilibili.com/video/BV1J1… 震惊!这位零基础前端同学在学习Java的第7天就可以研究Spring框架源码了!这是怎么做到的呢?噢!原来是站在了Java之父🐎士兵的肩膀上!
  • 相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论