三级缓存解决循环依赖的原理

Bean生命周期各阶段的解析参考:

整体概括

什么是循环依赖

两个bean,a与b,a中注入了b,b中注入了a,a与b相互依赖。这里就是发生了循环依赖,spring使用三级缓存处理循环依赖。

注意:必须是单例作用域的Bean才可以用三级缓存处理

什么是三级缓存

存放Bean的集合 (来自DefaultSingletonBeanRegistry中),用于解决循环依赖:

  1. 一级缓存,存放完全初始化好的Bean的集合,从这个集合中取出来的Bean可以立即返回

    java 复制代码
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  2. 二级缓存,存放已实例化,但没有初始化与属性注入的Bean的集合,二级缓存中的bean是从三级缓存中拿出来的

    java 复制代码
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
  3. 三级缓存,存放单实例Bean工厂(ObjectFactory)的集合,ObjectFactory里面是已实例化但没有依赖注入与初始化的bean

    java 复制代码
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

三级缓存解决循环依赖过程:

两个bean,ABA中需要注入BB中需要注入A

  1. 假设A先开始创建。A实例化阶段完成,此时A还没有进行属性注入,这时的早期 A 会存入三级缓存 (三级缓存会判断A是否要代理,需要就存A的代理类,不需要就存原始类)。然后进行属性注入,即注入B,此时B还不存在,这时会暂停A的注入,转而去创建B

  2. B开始创建,实例化完成后进入属性注入阶段,开始向B中注入A,此时会从三级缓存A(如果A有代理,拿到的就是A的代理类,没有代理拿到的就是原始对象)。因为上一步A已经存入到三级缓存 了,所以此处可以拿到一个早期的A,然后将A放入二级缓存,并将其从三级缓存 中删除。取到A后注入到B中,完成B的初始化。最后将完整的B放入一级缓存

  3. B成功完成初始化后,A继续生命周期流程,去注入B,此时B已经初始化好了,可以直接取到B了,然后将B注入A中,再把A存入一级缓存 。这时AB都成功完成了生命周期流程,如果后面还有依赖他们的其他Bean,便可以直接从一级缓存获取了。


涉及的源码

在容器运行过程的实例化阶段与初始化依赖注入阶段中,都涉及到循环依赖的处理,下面简单介绍两个阶段涉及循环依赖处理的源码。发生循环依赖时,主要就是下面源码的嵌套调用,简单了解即可,可以忽略直接看过程分析。

实例化时

回顾源码的方法调用过程:主启动类run() ----> refreshContext() ----> finishBeanFactoryInitialization() ----> preInstantiateSingletons()

实例化开始在DefaultListableBeanFactorypreInstantiateSingletons 方法中,它会执行getBean方法进行Bean创建:

getBean方法会调用doGetBean方法(AbstractBeanFactory内),在此方法内有两步循环依赖 的处理,两步处理都是使用getSingleton方法:

第一步处理:创建bean前先去一级缓存取,取到了就直接返回,不再执行创建过程,以此避免重复创建,节约性能。因为当一个Bean完成了实例化、属性注入、初始化的步骤后,它最后会被存入一级缓存中(下面会介绍这个存入的步骤)。

第二步处理 :在第一步没能从一级缓存拿到bean时,这里会将当前bean标记为正在创建中的状态,并调用createBean方法创建当前bean,创建好后在把bean存入一级缓存中,后面再有依赖当前bean的其他bean时,就可以直接从一级缓存中获取进行注入了

java 复制代码
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

	String beanName = transformedBeanName(name);
	Object beanInstance;

    // 第一步
    // 尝试从一级缓存中获取Bean,如果获取到则直接返回,避免重复创建,节约性能。
	Object sharedInstance = getSingleton(beanName);
    
	if (sharedInstance != null && args == null) {
		// logger.............
        
      // 处理从缓存中获取的bean实例,主要是判断该实例是普通的bean还是FactoryBean:
      //  1.如果是FactoryBean,并且请求的bean名称没有`&`前缀,则返回FactoryBean创建的Bean对象;否则,返回FactoryBean本身
      //  2.如果只是普通bean,则直接返回
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	 }
         
	 else {         
		//........
        
        // 第二步
        // 如果一级缓存中没有获取到bean,下面会进行创建。如果获取到这里就不执行了 
        // 此处的getSingleton方法涉及第二步循环依赖的处理,且方法参数与上面第一步的不同
        if (mbd.isSingleton()) {
 
        	sharedInstance = getSingleton(beanName, () -> {
        		try {
        			return createBean(beanName, mbd, args);
        		} // catch ......
        	});
        	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        } 
         
       //.............  
	 }
	
	 return adaptBeanInstance(name, beanInstance, requiredType);
	
}	

初始化时

实例化时执行的createBean方法会进入到AbstractAutowireCapableBeanFactorydoCreateBean方法,

doCreateBean方法通过createBeanInstance(beanName, mbd, args)创建出Bean实例后,就进入初始化阶段了。

初始化时也分为两步:

第一步是获取当前bean的早期引用,并将此引用存入三级缓存

第二步 是在依赖注入时执行getBean 方法获取需要注入的bean

java 复制代码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

	// ...........
    
	if (instanceWrapper == null) {
        //这里是Bean实例化
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
    
    
    // 下面是处初始化阶段:
    // ...........

	// 第一步循环依赖处理,获取早期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的引用,并将其放入三级缓存
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
       
    
	Object exposedObject = bean;
	try {
        // 第二步循环依赖处理,属性注入
		populateBean(beanName, mbd, instanceWrapper);
        // 这里是初始化,主要是执行`@PostConstruct`标注的初始化方法,不涉及循环依赖处理
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {} 
    
    //..............

	return exposedObject;
}    

下面分别介绍这两步处理源码


早期Bean的引用存入三级缓存

初始化阶段循环依赖的第一步处理:早期Bean的引用存入三级缓存

createBeanInstance方法实例化出Bean实例后,调用 SmartInstantiationAwareBeanPostProcessor 后置处理器的 getEarlyBeanReference 方法获取一个Bean实例的早期引用,然后将该引用存入三级缓存中:

  • getEarlyBeanReference方法会根据Bean实例 获取到Bean的引用
  • addSingletonFactory方法会将Bean的引用 存入三级缓存 singletonFactories
java 复制代码
/**
* 当前的Bean定义(mbd)必须同时满足如下3个条件:
*   1.是否是单例----isSingleton(), 因为三级缓存无法解决非单例bean的循环依赖
*   2.是否允许循环依赖----allowCircularReferences
*   3.该单例Bean当前是否正在创建中----isSingletonCurrentlyInCreation(beanName)
*
* 这里条件成立,因为实例化时第二步的getSingleton方法会把Bean标记为正在创建中的状态,且spring默认允许循环依赖
*
* */ 
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
	if (logger.isTraceEnabled()) {
		logger.trace("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
    // getEarlyBeanReference获取早期Bean的引用,调用的是SmartInstantiationAwareBeanPostProcessor后置处理器的实现
    // addSingletonFactory将早期Bean的引用存入三级缓存
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

先进入getEarlyBeanReference方法,此方法会去调用SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference实现,取到早期Bean的引用(早期Bean即实例化完成,但是还没有进行属性注入与初始化的bean):

java 复制代码
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
	
    // 置换引用,exposedObject是bean的一个副本、引用
    Object exposedObject = bean;
    
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        // 遍历后置处理器
		for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
            // 调用处理器的 获取早期引用方法
			exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
		}
	}
    
    // 返回引用
	return exposedObject;
}

进入SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法:

java 复制代码
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

    // 默认情况下,直接返回传入的原始bean实例,不做任何处理
	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

再进入addSingletonFactory内,把bean引用存入三级缓存

java 复制代码
// bean引用封装为ObjectFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
		if (!this.singletonObjects.containsKey(beanName)) {
            // singletonFactories就是三级缓存,这里把Bean存入三级缓存
			this.singletonFactories.put(beanName, singletonFactory);
            // 从二级缓存中移除此Bean
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}

依赖注入

初始化阶段循环依赖的第二步处理:依赖注入

populateBean方法是 Spring 容器中处理属性赋值与依赖注入的方法,负责将依赖注入的值设置到 bean 实例中。

进入该方法内,下面展示其处理依赖注入的关键部分,调用InstantiationAwareBeanPostProcessor处理器的postProcessProperties

java 复制代码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	
    // .................
 
    // 如果存在`InstantiationAwareBeanPostProcessor`则遍历这些后处理器,调用`postProcessProperties`方法,该方法用于执行依赖注入
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
        
        // 遍历`InstantiationAwareBeanPostProcessor`处理器实现
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            
            // 调用`postProcessProperties`方法,该方法允许后置处理器修改属性值,这里也是处理依赖注入的地方
            // `@Autowired`和`@Inject`等注解的处理就是在这个回调中实现的
			PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			
            // ............
            
            // 更新`pvs`为后置处理器修改后的值
			pvs = pvsToUse;
		}
	}
    
    // ...............
}

真正执行注入操作的是InstantiationAwareBeanPostProcessor处理器的实现类AutowiredAnnotationBeanPostProcessor,在它的postProcessProperties方法实现中:

  1. 会收集需要注入的依赖信息,将依赖信息封装为元数据
  2. 调用元数据对象的inject方法,该方法会获取当前Bean中每个需要被注入的属性Field和方法Method,依次对其进行注入操作
java 复制代码
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	
    // 第一步,收集需要注入的元数据信息
    // 依赖注入执行前,`MergedBeanDefinitionPostProcessor`处理器已经收集过了,所以这里可以直接从缓存中获取
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    
	try {
        // 第二步,执行注入
        // 将属性注入到目标Bean当中,内部循环遍历每一个需要注入的属性和方法进行注入
		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;
}

InjectionMetadata有两个实现类AutowiredFieldElementAutowiredMethodElement,分别代表属性注入方法注入 ,这里以属性注入为例,进入AutowiredFieldElementinject方法,它又有两步操作:

  1. 调用resolveFieldValue方法来解析并获取依赖
  2. 如果获取到依赖,方法最后会通过反射将依赖 注入到当前Bean属性中
java 复制代码
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    // 获取目标属性
	Field field = (Field) this.member;
	Object value;
    
    // 根据缓存标志决定如何获取注入值
	if (this.cached) {
		try {
            // 如果cached为true,则尝试从缓存中获取
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// 如果缓存中找不到,则进行解析获取
			value = resolveFieldValue(field, bean, beanName);
		}
	}
    
	else {
        // 如果cached为false,则直接调用resolveFieldValue来解析获取属性的值
		value = resolveFieldValue(field, bean, beanName);
	}
    
    // 执行反射注入
	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}

解析并获取依赖的过程在resolveFieldValue方法内,进入后看到beanFactory.resolveDependency

java 复制代码
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
	
    // ..............
    
	Object value;
	
    try {
        // 解析依赖,获取需要注入的值
        // 这个方法是Spring容器解析依赖的核心方法,它会根据依赖描述符(字段类型、注解等)从容器中找到需要的Bean
		value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
	}
	catch (BeansException ex) {
		throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
	}
    
    // ..............
    
    // 返回解析得到的值
	return value;
}

再进入beanFactory.resolveDependency,它会根据不同的依赖类型做不同的处理,最关键步骤是其内部调用的doResolveDependency方法:

java 复制代码
// descriptor:依赖描述符,封装了依赖的字段、方法参数等信息
// requestingBeanName:当前正在创建的Bean名称
// autowiredBeanNames:被注入的Bean名称
// typeConverter:类型转换器,用于类型转换
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    // ................
    
	if (result == null) {
    	// 这里是最关键的处理,进行实际的依赖解析
		result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
	}
		
    return result;
    
	}
}

进入doResolveDependency,它会真正去查找需注入的bean,此方法主要涉及:处理@Value注解、集合类型注入、获取依赖的bean、以及从多个满足注入条件的bean中选出唯一一个:

此方法内最重要的代码是descriptor.resolveCandidate,它会调用 getBean 方法获取需要注入的bean 。假设两个bean相互依赖,先创建的bean就是通过这里调用的getBean方法,来获取另一个bean为自己完成注入的。这时,就会重新循环到上面实例化步骤的doGetBean方法了。

java 复制代码
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	// ................
        
        
    // 如果候选对象是Class类型,则通过descriptor.resolveCandidate解析实际bean实例
	if (instanceCandidate instanceof Class) {
        // 此处的resolveCandidate会调用getBean方法,去获取需要注入的bean,此处也涉及了循环依赖
		instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
	}
        
        
	// .................
    
    Object result = instanceCandidate;
    
    // .........
    
    // 返回要注入的bean实例
	return result;
    
}

循环依赖过程分析

设计一个场景: 有两个单例bean,A与B,A中注入了B,B中注入了A。假设A先进行创建。

下面结合源码来分析循环依赖的处理过程:

第一步处理

容器启动,先进行bean-A的实例化,代码调用过程:主启动类run() ----> refreshContext() ----> finishBeanFactoryInitialization() ----> preInstantiateSingletons()

此时代码执行到DefaultListableBeanFactorypreInstantiateSingletons 方法中,它会执行getBean,再进一步调用doGetBean方法(AbstractBeanFactory内)进行A的创建:

doGetBean 方法逻辑 :先尝试从缓存中获取A,取不到就创建。注意这里有两个getSingleton方法,它很重要。

java 复制代码
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

	String beanName = transformedBeanName(name);
	Object beanInstance;

    // 第一步涉及循环依赖的处理
    // 尝试从多级缓存中获取A,如果获取到则直接返回,取不到就创建。由于A是第一次创建,这里取不到。
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {	
        // ...........       
	 }
    
     // 如果缓存中没有获取到A,下面调用createBean方法进行A的创建
	 else {
         
		//........                 
       
        if (mbd.isSingleton()) {
            
            // 第二步循环依赖的处理,创建A
        	sharedInstance = getSingleton(beanName, () -> {
        		try {
        			return createBean(beanName, mbd, args);
        		} // catch ......
        	});
        	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        } 
         
       //.............  
	 }
	
	 return adaptBeanInstance(name, beanInstance, requiredType);	
}	

先看第一步执的getSingleton方法,它从多级缓存 获取bean,具体代码在DefaultSingletonBeanRegistry中:

由于此时的A是第一次创建,容器中不存在A的实例,所以第一步的getSingleton方法一定返回空。

另外一点:如果是第一次创建A,代码走到这里时,还不会把A标记为正在创建中的bean,所以即便方法体内有从二三级缓存获取bean的逻辑,也不会执行。

java 复制代码
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	
    // 尝试从一级缓存获取A
	Object singletonObject = this.singletonObjects.get(beanName);
        
    // 此时一级缓存中并没有A,且A也没有被标记为正在创建中,此条件不成立,下面也不会执行
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
       
        // 尝试从二级缓存获取,如果找到直接返回,这里二级也没有
		singletonObject = this.earlySingletonObjects.get(beanName);
        
        // 如果前两级缓存都没有,且允许早期引用,进入同步块
		if (singletonObject == null && allowEarlyReference) {
            
			synchronized (this.singletonObjects) {
                // 再次检查一级缓存,防止其他线程已创建
				singletonObject = this.singletonObjects.get(beanName);
                // 如果一级缓存没 再次检查二级缓存
				if (singletonObject == null) {
					singletonObject = this.earlySingletonObjects.get(beanName);
                    
                    // 如果二级缓存仍然没有,从三级缓存获取,
                    // 如果三级缓存也没有,则此方法结束,走后面的创建流程
					if (singletonObject == null) {
						ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        // 如果三级缓存获取到了
						if (singletonFactory != null) {
                            // 通过ObjectFactory获取bean对象
							singletonObject = singletonFactory.getObject();
                            // 将对象放入二级缓存
							this.earlySingletonObjects.put(beanName, singletonObject);
                            // 从三级缓存移除bean
							this.singletonFactories.remove(beanName);
						}
					}
				}
			}
		}
	}
	return singletonObject;
}

下面看第二步的getSingleton


第二步处理

第一步的getSingleton获取为空后,进入doGetBean中第二个getSingleton方法,代码同样在DefaultSingletonBeanRegistry内,但参数列表与上一个不同:

第二步的getSingleton方法还会再次尝试从一级缓存获取A,当然还是获取不到,这时会有两步处理:

  1. 将A的beanName存入singletonsCurrentlyInCreation集合(一个用于存放正在创建中的单例bean的集合 ),也是就把A标记为正在创建中的bean (所以在第一次创建A时,前面第一步的getSingleton方法只会从一级缓存取)。
  2. 通过传入的ObjectFactory参数,以lamdba 形式调用createBean方法创建A。

第二步的getSingleton方法源码解析

java 复制代码
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    
    // 检查A的beanName非空
	Assert.notNull(beanName, "Bean name must not be null");
    
    // 加锁确保线程安全(单实例bean的创建线程)
    // singletonObjects是一级缓存,用于存放已经创建好的bean(已经实例化、初始化好的完整bean)
	synchronized (this.singletonObjects) {
        // 从一级缓存中获取A,如果存在则直接返回,这里取不到
		Object singletonObject = this.singletonObjects.get(beanName);
        
        // 此时一级缓存获取不到A,条件成立进入下面处理
		if (singletonObject == null) {
            
            // 如果一级缓存不存在A,检查A是否处于销毁状态,如果是则抛出异常。因为不允许在销毁过程中创建bean
			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!)");
			}
			
            // logger......
            
            // 将A的bean名称添加到`正在创建的单例bean集合`中,该集合名为singletonsCurrentlyInCreation 
            // 就是这里把A标记为了正在创建中的Bean
			beforeSingletonCreation(beanName);
            
			boolean newSingleton = false;
			boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<>();
			}
            
			try {
            	// 进行A的创建,这里的singletonFactory是传入的lamdba表达式,
                // 其实此处就是执行外面那个createBean方法来创建A
				singletonObject = singletonFactory.getObject();
                
 	
// 以此为界,本方法下面的代码先不用关注,先去看createBean创建A的流程...................................               
                
                // 如果创建成功,设置newSingleton标志为true,表示创建了新单实例bean-A
				newSingleton = true;
			}
			catch (IllegalStateException ex) {
				//...........
			}
            
            // 最后一定调用的
			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
                // 将A的bean名称从`正在创建的单例bean集合`中移除
				afterSingletonCreation(beanName);
			}
            
            // 如果成功创建了新的单实例bean-A,则将A的实例添加到一级缓存,并清除二、三级缓存。
			if (newSingleton) {
				addSingleton(beanName, singletonObject);
			}
		}
        // 最后返回A
		return singletonObject;
	}
}

第三步处理

接上面getSingleton中执行createBean,此时创建A的createBean方法会执行到AbstractAutowireCapableBeanFactorydoCreateBean方法,在doCreateBean中通过createBeanInstance方法创建出A实例,然后开始A的属性注入与初始化阶段:

初始化阶段循环依赖的第一步处理:将A的引用存入三级缓存

  • 调用SmartInstantiationAwareBeanPostProcessor处理器的getEarlyBeanReference方法,获取早期A的引用,这里的早期意思就是A还没进行属性注入与初始化
  • 调用addSingletonFactory将A的早期引用存入三级缓存 singletonFactories

如下是doCreateBean中涉及处理的源码解析:

java 复制代码
//................

if (instanceWrapper == null) {
    // 此处返回A的早期实例
	instanceWrapper = createBeanInstance(beanName, mbd, args);
}

//................省略部分源码,下面是循环依赖处理

/**
* 通过判断当前A的Bean定义(mbd):
*      1.是否是单例----isSingleton(),
*      2.是否允许循环依赖----allowCircularReferences,
*      3.该单例Bean当前是否正在创建中----isSingletonCurrentlyInCreation(beanName)
*
* 同时满足上面3个条件则进行早期单例bean的暴露:
*   A是单例,Spring默认允许循环依赖,且在第二步处理时A已被标记为正在创建中,此处条件成立。
*
* */ 
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
	if (logger.isTraceEnabled()) {
		logger.trace("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
    
    // getEarlyBeanReference获取早期A的引用,调用的是SmartInstantiationAwareBeanPostProcessor处理器的实现
    // addSingletonFactory将早期A的引用存入三级缓存
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

//................

spring默认允许循环依赖,A是单例,且前面第二步处理中,已经把A存入singletonsCurrentlyInCreation集合,也是就把A标记为正在创建中的bean,所以if条件成立:

先进入getEarlyBeanReference方法,获取引用。

这里调用的是SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法:

java 复制代码
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
	
    // 这里的bean就是A,exposedObject是A的一个副本,最后返回的也是这个副本
    // A到这里刚刚完成实例化,还没有进行属性注入与初始化,所以说获取的是早期A的引用,exposedObject就是A的引用。
    Object exposedObject = bean;
    
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        // 遍历后置处理器
		for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
            // 调用处理器方法,获取早期引用方
			exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
		}
	}
    
    // 返回早期引用
	return exposedObject;
}

进入SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法:

java 复制代码
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

    // 默认情况下,直接返回传入的A实例,不做任何处理,如果有存在代理的情况,调用的就是另一个实现了,这里就默认返回A实例
	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

然后进入addSingletonFactory内,把A的引用存入三级缓存

java 复制代码
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
		if (!this.singletonObjects.containsKey(beanName)) {
            // singletonFactories就是三级缓存,这里把A存入三级缓存
			this.singletonFactories.put(beanName, singletonFactory);
            // 从二级缓存中移除A,这里其实二级缓存中也还没有A
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}

第四步处理

上面存完A的引用到三级缓存后,进行A的依赖注入处理

在上面第三步获取到A的引用并存入三级缓存后,代码执行到如下源码的populateBean方法位置,进行属性注入:

java 复制代码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

	// ...........

	// 获取一个早期A的引用,并将其放入三级缓存
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
        // logger...........
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
          
	Object exposedObject = bean;
	try {
        // 属性注入
		populateBean(beanName, mbd, instanceWrapper);
        
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {
		
	}
      
    //..............
  

	return exposedObject;
}    

进入populateBean内部,它调用InstantiationAwareBeanPostProcessor处理器的postProcessProperties方法执行注入:

java 复制代码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	
    // .................

	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
        
        // 遍历`InstantiationAwareBeanPostProcessor`处理器的所有实现,处理`@Autowired`和`@Inject`等注解的依赖注入
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			
            // ............

		}
	}
    
    // ...............
}

实际执行依赖注入的实现类是AutowiredAnnotationBeanPostProcessor处理器,进入此处理器的postProcessProperties方法,该方法做两个操作:

  1. 收集A中需要注入的依赖信息,将依赖信息封装为元数据,元数据内包含的就是需要注入的B
  2. 调用元数据对象的inject方法,该方法会获取A中每个需要被注入的属性Field和方法Method,依次对其进行注入操作,这里会获取到B,然后将B注入到A中
java 复制代码
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	
    // 第一步,收集需要注入的元数据信息
    // 依赖注入执行前,`MergedBeanDefinitionPostProcessor`处理器已经收集过了,所以这里可以直接从缓存中获取
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    
	try {
        // 第二步,执行注入:先找到B实例,在注入到A中
		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;
}

InjectionMetadata有两个实现类AutowiredFieldElementAutowiredMethodElement,分别代表属性注入方法注入 ,这里假设B是A中的一个属性,所以会进入AutowiredFieldElementinject方法,它又执行两步操作:

  1. 调用resolveFieldValue方法来获取B
  2. 如果能取到B,通过反射把B注入到A中
java 复制代码
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    // 获取A中的B属性
	Field field = (Field) this.member;
	Object value;
    
    // 根据缓存标志决定如何获取注入值
	if (this.cached) {
		try {
            // 如果cached为true,则尝试从缓存中获取
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// 如果缓存中找不到,则重新解析
			value = resolveFieldValue(field, bean, beanName);
		}
	}
    
	else {
        // 如果cached为false,则直接调用resolveFieldValue来解析字段的值
		value = resolveFieldValue(field, bean, beanName);
	}
    
    // 执行反射注入
	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}

直接进入resolveFieldValue方法:

通过resolveFieldValue再进入doResolveDependency方法内

调用过程:resolveFieldValue ---> resolveDependency ---> doResolveDependency

doResolveDependency 方法内的 descriptor.resolveCandidate 会调用 getBean 方法获取需要注入的B

java 复制代码
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	// ................

	if (instanceCandidate instanceof Class) {
        // 此处的resolveCandidate会调用getBean方法,去获取B
		instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
	}
               
	// .................
    
    Object result = instanceCandidate;
    
    // .........
    
    // 如果上面处理无误,返回要注入的B
	return result;
    
}

执行到这,A的创建过程会暂停在依赖注入这一步,转而进行B的创建。


第五步处理

通过上面descriptor.resolveCandidate调用的getBean方法,获取B的实例,用于给A进行注入。

此时,获取B的getBean方法会重新回到AbstractBeanFactory.doGetBean方法进行B的创建,这里相当于又回到了第一步处理,不过这次是创建B了:

java 复制代码
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

	String beanName = transformedBeanName(name);
	Object beanInstance;

    // 尝试从一级缓存中获取B,如果获取到则直接返回。
    // 因为B还没有被创建,这里取不到,走下面的getSingleton
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		
        // ...........
        
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	 }
    
     // 如果一级缓存中没有获取到B,下面调用createBean进行B的创建
	 else {
         
		//........
                 
        // 创建B
        if (mbd.isSingleton()) {
            // 这里的getSingleton依然获取不到B
            // 但会把B存入正在创建的bean集合中,标记B为正在创建中的状态,然后执行createBean去创建B
        	sharedInstance = getSingleton(beanName, () -> {
        		try {
        			return createBean(beanName, mbd, args);
        		} // catch ......
        	});
        	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        } 
         
       //.............  
	 }
	
	 return adaptBeanInstance(name, beanInstance, requiredType);
	
}

同样,因为这时B也是第一次创建,doGetBean内的两个getSingleton都无法从缓存中获取到B。在把B标记为正在创建的状态后,走下面分支的createBean

createBean方法内调用doCreateBean,继续执行B的创建。


第六步处理

接第五步,进入到AbstractAutowireCapableBeanFactorydoCreateBean方法,在doCreateBean中通过createBeanInstance方法创建出B实例后,进入B的属性注入与初始化阶段:

这一步获取早期B的引用,将早期B的引用存入三级缓存

java 复制代码
//................

if (instanceWrapper == null) {
    // 此处返回B的早期实例
	instanceWrapper = createBeanInstance(beanName, mbd, args);
}

//................

// B是单例,spring默认允许循环依赖,且B已标记为正在创建中。这里条件成立
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");
	}
    // 获取早期B的引用,将早期B的引用存入三级缓存
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

//................

第七步处理

向三级缓存存完B的早期引用后,进入populateBean方法给B执行依赖注入

java 复制代码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

    // ...........
    
    // 获取一个早期B的引用,并将其放入三级缓存
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
       
    
	Object exposedObject = bean;
	try {
        // 执行B的属性注入
		populateBean(beanName, mbd, instanceWrapper);
        
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {} 
    
    //..............

	return exposedObject;
}    

这里依旧以属性注入为例,B中有一个A类型的属性需要被注入。

populateBean进一步调用AutowiredAnnotationBeanPostProcessorpostProcessProperties方法:

java 复制代码
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	
    // 第一步,收集需要注入的元数据信息
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    
	try {
        // 第二步,执行注入:去找A的实例,注入到B中
		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;
}

进入AutowiredFieldElementinject方法,它又执行两步操作:

  1. 调用resolveFieldValue方法来获取A
  2. 如果能取到A,通过反射把A注入到B中
java 复制代码
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    // 获取B中的A属性
	Field field = (Field) this.member;
	Object value;
    
    // 根据缓存标志决定如何获取注入值
	if (this.cached) {
		try {
            // 如果cached为true,则尝试从缓存中获取
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// 如果缓存中找不到,则重新解析
			value = resolveFieldValue(field, bean, beanName);
		}
	}
    
	else {
        // 如果cached为false,则直接调用resolveFieldValue来解析字段的值
		value = resolveFieldValue(field, bean, beanName);
	}
    
    // 执行反射注入
	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}

这里直接进入doResolveDependency方法内(调用过程为resolveFieldValue ---> resolveDependency ---> doResolveDependency

通过resolveCandidate调用getBean 方法获取需要注入的A:

java 复制代码
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	// ................

	if (instanceCandidate instanceof Class) {
        // 此处的resolveCandidate会调用getBean方法,去获取A
		instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
	}
               
	// .................
    
    Object result = instanceCandidate;
    
    // .........
    
    // 如果上面处理无误,返回要注入的A
	return result;
    
}

第八步处理

通过上面descriptor.resolveCandidate调用的getBean方法,去获取A的实例,用于给B进行注入。

此时,获取B的getBean方法会重新回到doGetBean方法(AbstractBeanFactory内)进行A的创建,这里相当于又回到了第一步处理,进行A的二次获取:

java 复制代码
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

	String beanName = transformedBeanName(name);
	Object beanInstance;

    // 尝试从多级缓存中获取A,这里会从三级缓存中拿到A,因为之前的第三步处理已经把A存进去了
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		
        // ...........
        
        // 此处会判断A是工厂bean还是普通bean,不同类型做不同处理,最后还是返回A的实例
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	 }
    
         
	//............              
	
	 return adaptBeanInstance(name, beanInstance, requiredType);
	
}

最关键的部分来了,A在前面的创建过程中:

  • 第二步处理时,A被标记为正在创建中的bean
  • 第三步处理时,已经通过SmartInstantiationAwareBeanPostProcessor处理器的getEarlyBeanReference方法,获取到早期A的引用存入了三级缓存

所以此处可以直接从三级缓存 获取到A(注意这里取到A后会把它从三级缓存 删除,并存到二级缓存 中),来给B进行注入,不需要在执行createBean方法进行实例化、初始化那一套了:

java 复制代码
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	
    // 尝试从一级缓存获取完全初始化好的A,如果找到直接返回,这里取不到
	Object singletonObject = this.singletonObjects.get(beanName);
    
    
    // 如果一级缓存没有,且该bean正在创建中,可能涉及循环依赖
    // 这里的条件判断成立,因为一级缓存没取到,前面A的创建过程中它已经被标记为正在创建中了
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        
        // 尝试从二级缓存获取,此时二级缓存没有A
		singletonObject = this.earlySingletonObjects.get(beanName);
        
        // 如果前两级缓存都没有,且允许早期引用,进入同步块
		if (singletonObject == null && allowEarlyReference) {
            
			synchronized (this.singletonObjects) {
                // 再次检查一级缓存,防止其他线程已创建
				singletonObject = this.singletonObjects.get(beanName);
                // 如果一级缓存没 再次检查二级缓存
				if (singletonObject == null) {
					singletonObject = this.earlySingletonObjects.get(beanName);
                    
                    // 如果二级缓存仍然没有,从三级缓存获取,这里可以取到A
					if (singletonObject == null) {
						ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        // 如果三级缓存获取到了A
						if (singletonFactory != null) {
                            // 通过ObjectFactory获取A的对象实例
							singletonObject = singletonFactory.getObject();
                            // 将A实例放入二级缓存
							this.earlySingletonObjects.put(beanName, singletonObject);
                            // 从三级缓存移除A
							this.singletonFactories.remove(beanName);
						}
					}
				}
			}
		}
	}
    // 返回A
	return singletonObject;
}

第九步处理

获取到A后,回到第七步处理后面的doResolveDependency方法内,再向上返回到AutowiredFieldElementinject方法,在inject方法完成注入,即把A注入到B中。

然后执行剩余的初始化initializeBean方法(此方法不涉及循环依赖处理了),最后返回已完成整个创建流程的完整B:

java 复制代码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

    // ...........
    
    // 获取一个早期B的引用,并将其放入三级缓存
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
       
    
	Object exposedObject = bean;
	try {
        // 执行B的属性注入
		populateBean(beanName, mbd, instanceWrapper);
        
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {} 
    
    //..............

    // 返回B
	return exposedObject;
} 

第十步处理

B创建完成后,继续执行A的注入流程。

这时第九步处理中的doCreateBean方法,会将创建完成的B返回下面的createBean方法中,这里相当于回到了第五步处理中:

java 复制代码
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {       
		//........
                 
        if (mbd.isSingleton()) {
        	sharedInstance = getSingleton(beanName, () -> {
        		try {
        			return createBean(beanName, mbd, args);
        		} // catch ......
        	});
        	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        } 
         
       //.............  
	 }
	
	 return adaptBeanInstance(name, beanInstance, requiredType);
	
}

此时doCreateBean方法取到了B的实例,然后在getSingleton方法中将B实例存入到了一级缓存

java 复制代码
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    
    // ........
            
			try {
            	// 这里执行的就是createBean,singletonObject就是创建完成的B
				singletonObject = singletonFactory.getObject();
                // 如果创建成功,设置newSingleton标志为true,表示创建了新单实例bean-B
				newSingleton = true;
			}
			catch (IllegalStateException ex) {
				//...........
			}
    
    		//..........
            
            // 如果成功创建了新的单实例bean-B,则将B的实例添加到一级缓存,并清除二、三级缓存。
			if (newSingleton) {
				addSingleton(beanName, singletonObject);
			}
		}
        // 最后返回B
		return singletonObject;
	}
}

返回到descriptor.resolveCandidate处。


第十一步处理

descriptor.resolveCandidate将B实例返回到doResolveDependency,进而再返回到AutowiredAnnotationBeanPostProcessorpostProcessProperties方法去执行inject(这里是回到了第四步处理),将B注入到A中:

java 复制代码
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	
    // 第一步,收集需要注入的元数据信息
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    
	try {
        // 第二步,执行注入:先找到B实例,在注入到A中
		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;
}

执行完这里后,A的依赖注入就完成了,后面会执行初始化(不涉及循环依赖处理)。最后一路返回到第二步处理的getSingleton方法:

重要的两个处理:

  1. 把A从正在创建的Bean的集合中移除
  2. 把A存入一级缓存,从二三级缓存中移除A
java 复制代码
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    
    // .................
            
    	// 这里的singletonObject就是完成依赖注入与初始化的A
		singletonObject = singletonFactory.getObject();                        
        // 如果创建成功,设置newSingleton标志为true,表示创建了新单实例bean-A
		newSingleton = true;


		finally {
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = null;
			}
             // 将A的bean名称从`正在创建的单例bean集合`中移除
			afterSingletonCreation(beanName);
		}
            
        // 如果成功创建了新的单实例bean-A,则将A的实例添加到一级缓存,并清除二、三级缓存中的A。
		if (newSingleton) {
			addSingleton(beanName, singletonObject);
		}
	}

        // 最后返回A
		return singletonObject;
	}
}

经过这个完整的过程后,A与B都作为完整的Bean被存入了一级缓存。后面在有其他的Bean依赖A或B,便可以直接在doGetBean

方法中,通过第一个getSingleton从一级缓存拿到A或B进行注入了


总体梳理

有两个bean,A与B,A中注入了B,B中注入了A。假设A先进行创建,执行doGetBean方法创建A:

  1. doGetBean方法中,会先使用getSingleton方法通过AbeanName,尝试去一二三级缓存中获取A的实例,因为A 是第一次创建所以这里取不到

    (会先去一级缓存去,当一级缓存取不到且A 处于正在创建中的状态时,才会再去二三级缓存取。这里A是第一次创建,一级缓存没有,也没有被标记为正在创建中)

  2. 上面取不到就进行A 的创建,会在doGetBean方法内另一个重载的getSingleton方法中执行创建,该getSingleton方法会先把A 标记为正在创建中,然后调用createBean方法创建A

  3. createBean进一步执行到doCreateBean方法,doCreateBean会先把早期(没有属性注入与初始化)A 实例的引用存入三级缓存,然后在执行populateBean方法对A进行属性注入

  4. populateBean方法调用AutowiredAnnotationBeanPostProcessor处理器的postProcessProperties方法,先收集A 中需要注入的属性,即B ,然后执行把B 注入到A 中的注入操作(AutowiredFieldElementinject方法)

  5. 进入AutowiredFieldElementinject方法,通过如下的调用流程一直调用到getBean,用getBean获取B 来给A 进行注入:
    inject ---> resolveFieldValue ---> resolveDependency ---> doResolveDependency ---> resolveCandidate ---> getBean

  6. 暂停A 的处理,进入创建B 的过程。getBean调用doGetBean创建B ,这里相当于循环回到了第一步, 还是在doGetBean方法中先使用第一个getSingleton方法通过BbeanName,去一二三级缓存中取B ,因为B这里也是第一次创建所以取不到

  7. 进入doGetBean的第二个getSingleton方法,因为B 此时也是第一次创建,所以还是取不到。这时B 被标记为正在创建中,并执行createBean方法创建B

  8. 创建B的createBean进一步执行到doCreateBean方法,doCreateBean会先把早期(没有属性注入与初始化)B 实例的引用存入三级缓存,然后在执行populateBean方法对B进行属性注入

  9. 处理BpopulateBean方法调用AutowiredAnnotationBeanPostProcessor处理器的postProcessProperties方法,先收集B 中需要注入的属性,即A ,然后执行AutowiredFieldElementinject方法把A 注入到B

  10. 进入AutowiredFieldElementinject方法,还是按照第5 小步的调用流程一直调用到getBean,用getBean获取A 来给B进行注入:

  11. B 中获取AgetBean调用doGetBean,这时在doGetBean的第一个getSingleton方法中,虽然一级缓存获取不到,但是在第2 步中A 被标记为正在创建中,所以此处三级可以获取到A

  12. 把从三级缓存获取到的A 返回到第10 步的AutowiredFieldElement.inject方法处,把A 注入到B 中,此时完成了B的依赖注入。

  13. 完成B的依赖注入后,继续向上返回,到第7 步创建BgetSingleton方法中执行的createBean,这个createBean返回B 实例,在getSingleton方法中把B存入一级缓存并返回

  14. 回到第6 步,继续A 的注入,把B 注入到A 中,A完成依赖注。然后通过createBean方法将完整的A 实例返回到doGetBean中的getSingleton方法(第2步),把A从正在创建中的的Bean集合中移除、并存入一级缓存。

  15. 最后A与B都完成了创建,再有其他的Bean依赖他们时,便可在doGetBean内的第一个getSingleton方法处,直接从一级缓存拿到A或B进行注入了


延申

其他解决循环依赖的方法

除三级缓存外,也可通过@Lazy注解解决循环依赖,其原理是通过延迟加载来打破循环依赖的链。具体来说,当两个或多个Bean相互依赖时,如果使用@Lazy注解,Spring容器在创建Bean时不会立即注入依赖的Bean,而是注入一个代理对象。当实际需要调用代理对象的方法时,才会去初始化真正的Bean。

关于构造器注入的循环依赖

三级缓存无法解决构造器注入的循环依赖,是因为构造器注入发生在 Bean 实例化阶段,而三级缓存机制依赖于 Bean 已经完成实例化。虽然实例化前会有从一二三级缓存获取bean实例的操作,但是因为bean没有完成实例化及后续步骤,所以获取不到

三级缓存无法解决构造器注入循环依赖的根本原因

  1. 时机不匹配:构造器注入发生在 Bean 实例化阶段,而三级缓存机制要求 Bean 必须先完成实例化才能暴露早期引用。
  2. 依赖顺序:构造器参数必须在实例化之前就解析完成,此时当前 Bean 还没有被创建,无法提供早期引用。
  3. 设计限制:Spring 的设计决定了构造器注入是"全有或全无"的操作,要么所有依赖都可用并成功创建实例,要么失败。
相关推荐
汤姆yu3 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶3 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip5 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
JavaGuide5 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
figo10tf5 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
zhangyi_viva6 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
橙露6 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot
程序员敲代码吗6 小时前
Spring Boot与Tomcat整合的内部机制与优化
spring boot·后端·tomcat
NuageL6 小时前
原始Json字符串转化为Java对象列表/把中文键名变成英文键名
java·spring boot·json
jzheng86106 小时前
Spring Boot(快速上手)
java·spring boot·后端