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

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 的设计决定了构造器注入是"全有或全无"的操作,要么所有依赖都可用并成功创建实例,要么失败。
相关推荐
WZTTMoon2 小时前
Spring 配置解析与 @Value 注入核心流程详解
java·spring boot·spring
程序定小飞3 小时前
基于springboot的健身房管理系统开发与设计
java·spring boot·后端
wxin_VXbishe3 小时前
springboot在线课堂教学辅助系统-计算机毕业设计源码07741
java·c++·spring boot·python·spring·django·php
南山十一少3 小时前
基于 Spring Boot 与 RabbitMQ 的分布式消息通信机制设计与实现
spring boot·分布式·java-rabbitmq
华仔啊3 小时前
开源一款 SpringBoot3 + Vue3 数据库文档工具,自动生成 Markdown/HTML
vue.js·spring boot·后端
合作小小程序员小小店4 小时前
web网页开发,在线%就业信息管理%系统,基于idea,html,layui,java,springboot,mysql。
java·前端·spring boot·后端·intellij-idea
陈果然DeepVersion4 小时前
Java大厂面试真题:从Spring Boot到AI微服务的三轮技术拷问(一)
java·spring boot·redis·微服务·kafka·面试题·oauth2
爱吃程序猿的喵5 小时前
Spring Boot 常用注解全面解析:提升开发效率的利器
java·spring boot·后端
熙客6 小时前
SpringBoot项目如何使用Log4j2+SLF4J构建日志
java·spring boot·log4j