Spring 循环依赖


内容总结

三级缓存

  • singletonObjects: 单例对象, 单例池, 存放经过完整创建流程的单例对象, 可能是原始对象或代理对象
  • earlySingletonObjects: 早期单例对象, 二级缓存, 存放有循环依赖问题且没有走完创建流程的早期单例对象, 可能是原始对象或代理对象
  • singletonFactories: 单例工厂, 是解决循环依赖的关键, 单例在实例化后就会被以 Lambda 的形式加入到该缓存, 发生循环依赖时才会被使用到. 该 Lambda 被执行后会将原始对象经过 AOP 处理, 有需要则生成代理对象, 否则返回原始对象, 最终放入二级缓存
  • singletonsCurrentlyInCreation: 创建单例前会将其 BeanName 加入到该 Set, 依赖注入时如果发现需要被注入的 Bean 正在被创建, 则说明该 Bean 出现了循环依赖
  • earlyProxyReferences: 发生循环依赖后, 会提前走 AOP 流程, 会将唯一标识加入该 Map, 在初始化后阶段, 再次走 AOP 流程时, 会根据该 Map 中是否存在唯一标识, 决定是否走 AOP 流程. 经过 AOP 流程并不是说已经变成代理对象, 流程会判断是否需要生成代理, 有被切到才会生成并返回代理对象, 没被切到则会返回原始对象

循环依赖

循环依赖只存在于 Spring 中, 是因为 Spring 创建 Bean 的流程中, 依赖注入阶段, 会先从单例池中找, 没有再从定义池中找, 针对定义池中找到的候选项会通过 getBean 创建其单例并缓存到单例池, 此机制导致了存在循环依赖的问题. 如 A 依赖 B, B 依赖 A, getBean A 的时候, A 还没有入单例池. 发现依赖 B, 又去 getBean B, 又发现依赖 A, 在单例池中没有找到 A, 在定义池中找到了 A, 所以又去 getBean A, …, Spring 通过三级缓存的方式, 解决了这个问题

Spring 完成依赖注入的核心方法是 BeanFactory.resolveDependency, 做先类型后名称的筛选, 取到符合条件的候选项, 候选项如果来自单例池, 则是一个 Bean, 如果来自定义池, 则就是一个 Class 对象, 在这里会对其的 BeanName 做 getBean 操作, 生成 Bean 并缓存到单例池. 这个流程可以简化为, Spring 创建 Bean 的流程中的依赖注入阶段, 会对其依赖做 getBean 操作

其中 findAutowireCandidates 步骤会从单例池和定义池中找符合类型条件的 BeanName, 如果当前依赖的 Bean 还没有被生成单例并缓存, 则在单例池中找不到, 就会去定义池中找, 定义池中通过遍历 beanDefinitionNames 的方式拿到每一个 BeanDefinition, 第一步就是判断是否为 FactoryBean, 内部就会判断 beanClass 字段中的全限定类名是否被加载成为 Class 对象, 没有就会执行类加载, 并缓存结果

循环依赖的解决方案设计

模拟循环依赖

假设有AB两个类, A依赖B且B依赖A, 遍历创建单例Bean时先A再B, A依赖B所以去创建B, B依赖A所以去创建A, 陷入循环

@Component
public class A {
    
    
	@Autowired
	private B b;
}
@Component
public class B {
    
    
	@Autowired
	private A a;
}

在这里插入图片描述

解决循环依赖的关键 缓存

需要提前暴露A, 让B找的到A, 即增加一个缓存, 即可打破循环依赖. 该缓存就是解决循环依赖的关键
在这里插入图片描述

仍然存在问题 代理

假设被aop切到, 最终会生成代理对象, 则现有逻辑会导致, 加入单例池的是代理对象, 被注入的是原始对象, 不符合单例设计
在这里插入图片描述

解决代理问题的关键 提前AOP

只要在加入缓存前, 提前执行aop, 就能保证单例. 不管是否需要aop, 最终被注入的和加入单例池的一定是同一个对象
在这里插入图片描述

仍然存在问题 AOP全部提前与Bean创建流程设计严重不符

在Spring关于Bean创建流程的设计中, AOP是发生在初始化(后)阶段的, 现在把AOP全部提前到实例化后, 严重违背设计

解决违背设计的关键 尽量提前而非全部提前 判断是否发生循环依赖

要想解决循环依赖问题, 新增缓存与提前AOP是必不可少的手段, 但其实没必要把所有的AOP都提前, 涉及到循环依赖的AOP提前即可, 不涉及循环依赖的还是在初始化(后)阶段做AOP, 这样更为符合Spring中Bean创建流程的设计规范

既然想将涉及到循环依赖的AOP提前, 那就得先判断是否发生了循环依赖. 结合模拟流程发现, 只根据一个类, 无法判断是否循环依赖, 必须得借助依赖注入的流程, 在需要注入Bean时发现该Bean正在创建中, 即可说明该Bean发生循环依赖了

代码实现即是, 在创建Bean之前, 将BeanName加入一个Set(我称之为创建池), 标记该Bean正在创建, 走完流程, 加入单例池后, 从Set中移除.创建Bean之前, 检查这个Set, 如果存在, 说明该Bean正在创建中, 说明该Bean发生循环依赖了
在这里插入图片描述

仍然存在问题 多重循环

假设a依赖bc, b依赖a, c依赖a, 则按照现有逻辑, b和c注入的a不是同一个
在这里插入图片描述

解决多重循环的关键 再加一层缓存

由上图可知, b注入a和c注入a时, 各自创建了一个a的代理对象, 只需要额外加一层缓存, 即可让bc注入的a是同一个对象
在这里插入图片描述

总结

自此, 循环依赖以及相关问题, 全部得到了解决, 引入了两个缓存, 一个机制(AOP提前)

  • 缓存1, 放的是早期的原始对象, 不管是否循环依赖, 在Bean实例化后都会加入到缓存1
  • 缓存2, 放的是有循环依赖问题的Bean的早期实例, 可能是原始对象, 也可能是代理对象, 但一定是发生了循环依赖的Bean才会加入缓存2, 位置是在 doGetBean 的 getSingleton 内部, 从三级缓存中找到 Lambda 并执行, 将结果存入二级缓存

这里的缓存2, 其实就是 Spring 中的二级缓存 earlySingletonObjects, 早期单例对象, 存放发生循环依赖但没有走完创建流程的早期单例
这里的缓存1, 其实就是 Spring 中的 三级缓存 singletonFactories, 单例工厂, 用于将原始对象经过 AOP 包装成代理对象, 放入二级缓存
再加上单例池这个一级缓存, 就构成了 Spring 解决循环依赖问题的 三级缓存 机制

源码

大致流程 a依赖bc, b依赖a, c依赖a, 解决循环依赖

  • getBean(“a”)
  • doGetBean(“a”)
  • getSingleton(“a”), 在单例池中查找, 判断a未发生循环依赖, 不走二三级缓存查找流程, 最终未找到a, 走创建流程
  • mbd.isSingleton(), 判断是单例, 走单例创建流程
  • getSingleton(beanName, () -> createBean(beanName, mbd, args)), 单例创建流程, 将 createBean 作为 Lambda 传入
  • beforeSingletonCreation, 将BeanName添加到标记正在创建的Bean的singletonsCurrentlyInCreation中
  • 调用 Lambda 的 singletonFactory.getObject(), 即调用 createBean
  • createBean(beanName, mbd, args)
  • doCreateBean(beanName, mbdToUse, args)
  • a加入创建池
  • a的实例化
  • addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)), 将 getEarlyBeanReference 作为 Lambda 添加到三级缓存
  • 依赖注入, a需要一个b对象
    • getBean(“b”), 未找到
    • b加入创建池
    • b的实例化
    • 依赖注入, b需要一个a对象
      • getBean(“a”)
      • getSingleson(“a”), 发现a循环依赖了, 从二三级缓存中找a, 从三级缓存中找到了a, 执行其Lambda表达式, 即执行 getEarlyBeanReference 方法, 判断是否需要aop, 需要的话生成并返回代理对象, 不需要的话返回原始对象, 加入二级缓存, 从三级缓存中移除, 最终返回a
    • 完成b需要a的注入
    • b的初始化
    • b的初始化后, 是否需要aop? 是否已经aop? 执行aop, 返回a
    • b加入单例池
    • b移出创建池
  • 完成a需要b的注入
  • 依赖注入, a需要一个c对象
    • getBean(“c”), 未找到
    • c加入创建池
    • c的实例化
    • 依赖注入, c需要一个a对象
      • getBean(“a”)
      • getSingleson(“a”), 发现a循环依赖了, 从二级缓存中找a, 找到了, 最终返回a
    • 完成c需要a的依赖注入
    • c的初始化
    • c的初始化后, 是否需要aop? 是否已经aop? 执行aop, 返回a
    • c加入单例池
    • c移出创建池
  • a的初始化
  • a的初始化后, 是否需要aop? 是否已经aop? 执行aop, 返回a
  • a加入单例池
  • a移出创建池

getBean

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

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

	// 传入的 name 转换成为 BeanName
	// name 可能是 &xxx 和 xxx, 如果传入的是 &xxx, 则转成的 BeanName 就是 xxx, FactoryBean 存在单例池中, 其 key 就是不加 & 符号的 BeanName
	// name 可能是 BeanName 的别名(或别名的别名), 最终返回的一定是 BeanName
	String beanName = transformedBeanName(name);
	Object beanInstance;

	// Eagerly check singleton cache for manually registered singletons.
	// 从单例池中取到该 Bean, 首次获取肯定是没有的, 需要走创建流程, 创建好后才会放进单例池
	// 即使是原型 Bean 也会先尝试从单例池中获取, 因为 Spring 中绝大多数都是单例 Bean
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
    
    
		if (logger.isTraceEnabled()) {
    
    
			if (isSingletonCurrentlyInCreation(beanName)) {
    
    
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
    
    
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		// 如果单例池中已经有了该 Bean
		// 传入的是 Name 和 BeanName
		// 不管是不是 FactoryBean, 都是从这里获取, 有三种情况
		// 1. 获取与 FactoryBean 无关的普通 Bean
		// 2. 获取 FactoryBean 本身
		// 3. 获取 FactoryBean 的 getObject Bean(默认是在这里调用并创建)
		// 记住这个方法名称, 它主要用来处理 FactoryBean, getBean 的流程中, 拿到 Bean 对象后, 都会调用该方法
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	// 单例池中不存在 Bean, 走创建流程
	else {
    
    
		
		// ...

		// 真正开始创建 Bean
		try {
    
    
			if (requiredType != null) {
    
    
				beanCreation.tag("beanType", requiredType::toString);
			}
			// 获取合并的 BeanDefinition, 校验不是抽象的 BeanDefinition
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// Guarantee initialization of beans that the current bean depends on.
			// @DependsOn 注解表明要创建该 Bean 需要先把该注解指定的 Bean 创建好
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
    
    
				for (String dep : dependsOn) {
    
    
					// todo @DependsOn
					// 判断当前要创建的 BeanName 是否被 dep 依赖了, 其实就是循环依赖了, 这种循环依赖不解决, 直接报错
					// AB 两者通过 @DependsOn 注解互为依赖
					if (isDependent(beanName, dep)) {
    
    
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					// dep 被 beanName 依赖了, 依赖与被依赖的关系存入 dependentBeanMap 和 dependenciesForBeanMap 中
					registerDependentBean(dep, beanName);
					try {
    
    
						// 创建依赖的 Bean
						getBean(dep);
					} catch (NoSuchBeanDefinitionException ex) {
    
    
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			// Create bean instance.
			// 单例 Bean
			if (mbd.isSingleton()) {
    
    
				// 注意这里的 getSingleton 传入的是一个 Lambda 表达式, 即传入的代码会在 getSingleton 中的某个地方执行, 一定不是现在就执行
				sharedInstance = getSingleton(beanName, () -> {
    
    
					try {
    
    
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
    
    
						// Explicitly remove instance from singleton cache: It might have been put there
						// eagerly by the creation process, to allow for circular reference resolution.
						// Also remove any beans that received a temporary reference to the bean.
						destroySingleton(beanName);
						throw ex;
					}
				});
				// 处理 FactoryBean, 任何作用域的 Bean 都可能是一个 FactoryBean
				beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

			// 原型 Bean
			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);
				}
				// 处理 FactoryBean, 任何作用域的 Bean 都可能是一个 FactoryBean
				beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}

			// 其他 Scope 的 Bean
			// SpringMVC 还有 request / session / application 等 Scope, 配置 @RequestScope
			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);
						}
					});
					// 处理 FactoryBean, 任何作用域的 Bean 都可能是一个 FactoryBean
					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();
		}
	}

	// 校验通过 name 获取到的 beanInstance 是否是 requiredType, 对应传入了 requiredType 的 getBean 方法
	return adaptBeanInstance(name, beanInstance, requiredType);
}

getSingleton

public Object getSingleton(String beanName) {
    
    
	return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
	// Quick check for existing instance without full singleton lock
	Object singletonObject = this.singletonObjects.get(beanName);

	// 如果单例池中没有, 且本Bean发生了循环依赖(需要注入Bean时发现Bean正在创建中), 则从二级缓存(早期单例池)中找
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    
		singletonObject = this.earlySingletonObjects.get(beanName);

		// 如果二级缓存中没有, 则从三级缓存中找, 找到Lambda表达式
		// 判断是否需要Aop, 需要则生成并返回代理对象, 否则返回原始对象, 加入二级缓存, 移除三级缓存
		if (singletonObject == null && allowEarlyReference) {
    
    
			synchronized (this.singletonObjects) {
    
    
				// Consistent creation of early reference within full singleton lock
				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) {
    
    
							// 执行 Lambda getEarlyBeanReference, 如果有需要aop, 则执行aop生成并返回代理对象, 否则返回原始对象
							singletonObject = singletonFactory.getObject();
							this.earlySingletonObjects.put(beanName, singletonObject);
							this.singletonFactories.remove(beanName);
						}
					}
				}
			}
		}
	}
	return singletonObject;
}

getSingleTon, doGetBean 中 mbd.isSingleton() 分支内

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) {
    
    
			
			// 将BeanName添加到标记正在创建的Bean的singletonsCurrentlyInCreation中,后面就可以检查是否循环依赖了
			beforeSingletonCreation(beanName);
			boolean newSingleton = false;
			
			try {
    
    
				// 调用传入的 Lambda 表达式, 即在这里执行 createBean
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			}
			catch (IllegalStateException ex) {
    
    
				// Has the singleton object implicitly appeared in the meantime ->
				// if yes, proceed with it since the exception indicates that state.
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
    
    
					throw ex;
				}
			}
			catch (BeanCreationException ex) {
    
    
				if (recordSuppressedExceptions) {
    
    
					for (Exception suppressedException : this.suppressedExceptions) {
    
    
						ex.addRelatedCause(suppressedException);
					}
				}
				throw ex;
			}
			finally {
    
    
				if (recordSuppressedExceptions) {
    
    
					this.suppressedExceptions = null;
				}
				
				// 将BeanName从singletonsCurrentlyInCreation中移除
				afterSingletonCreation(beanName);
			}
			if (newSingleton) {
    
    
				// 将创建的单例 Bean 添加到单例池中
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
    
    
	RootBeanDefinition mbdToUse = mbd;

	// todo 类加载, 解析 BeanDefinition 中的 beanClass 字段, 将其解析为 Class 对象
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    
    
		mbdToUse = new RootBeanDefinition(mbd);
		// 将解析的 Class 替换掉原来的 beanClass 值
		mbdToUse.setBeanClass(resolvedClass);
	}

	// 和 @LookUp 有关
	mbdToUse.prepareMethodOverrides();

	// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
	// todo 实例化前
	// 该步骤用的很少
	// BeanPostProcessor
	// 执行 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法
	// 如果该步骤返回了 Bean, 则 Bean 生命周期的后续流程就不走了(初始化后除外), 相当于 createBean 已经完成了
	// BeanPostProcessor 支持在 初始化前 和 初始化后 执行一些操作
	// BeanPostProcessor 的子接口 InstantiationAwareBeanPostProcessor, 额外支持在 实例化前 和 实例化后 执行一些操作
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
    
    
		return bean;
	}

	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}

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

	// Instantiate the bean.
	// todo 实例化
	// BeanWrapper 里面有 Bean 和 BeanType
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
    
    
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
    
    

		// 创建 Bean 实例, 推断构造方法 就在这里
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	if (beanType != NullBean.class) {
    
    
		mbd.resolvedTargetType = beanType;
	}

	// Allow post-processors to modify the merged bean definition.
	synchronized (mbd.postProcessingLock) {
    
    
		if (!mbd.postProcessed) {
    
    
			try {
    
    
				// 实例化全流程=实例化前,实例化,实例化后
				// 实例化前 = InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation, 在 createBean 内部
				// 实例化后 = InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation, 在 populateBean 内部

				// todo AutowiredAnnotationBeanPostProcessor 寻找依赖注入点就是在这个流程完成的
				// BeanPostProcessor
				// 执行 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 方法
				// 用来处理 BeanDefinition, 修改其内容, 或者给某些字段赋值什么的
				// Spring 提供了一个默认实现, AutowiredAnnotationBeanPostProcessor
				// 找到需要执行注入的字段和方法(@Autowired / @Value / javax.inject.Inject)并缓存起来, 后面依赖注入的时候就不用找了, 直接拿来用就行
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
    
    
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Post-processing of merged bean definition failed", ex);
			}
			mbd.postProcessed = true;
		}
	}

	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	// 为了解决循环依赖, 提前缓存单例创建工厂
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			// 如果当前 BeanName 正在创建中, 则启用三级缓存 singletonFactories
			// 即创建的所有单例Bean都会添加到三级缓存中, 因为创建原型Bean之前, 并不会执行标记创建 beforeSingletonCreation
			// 在创建中并不能说明是发生循环依赖, 必须是需要注入某个Bean的时候发现创建中, 才能说明是发生循环依赖
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
    
    
		if (logger.isTraceEnabled()) {
    
    
			logger.trace("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		// 不管是否循环依赖, 实例化后都添加到三级缓存
		// todo 三级缓存是解决循环依赖的关键
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
    
    

		// todo 依赖注入(属性填充)
		// 当前正在创建的是 beanName, 这一步就是给 beanName 填充属性
		populateBean(beanName, mbd, instanceWrapper);

		// todo 初始化
		// 假如需要 AOP, 如果发生循环依赖, 初始化后不走 AOP, 返回的其实是原始对象, 而不是代理对象. 所以后面有额外的处理逻辑
		// 假如需要 AOP, 如果没有循环依赖, 初始化后要走 AOP, 返回的是代理对象
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {
    
    
		if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
    
    
			throw (BeanCreationException) ex;
		}
		else {
    
    
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
		}
	}

	// 如果支持循环依赖
	if (earlySingletonExposure) {
    
    
		// allowEarlyReference=false, 即只允许到一二级中查找, 即从二级缓存中查找
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
    
    
			if (exposedObject == bean) {
    
    
				// 当二级缓存中有, 且初始化返回的对象和原始 Bean 是同一个对象时, 将刚刚初始化阶段返回的结果替换成二级缓存中的对象
				exposedObject = earlySingletonReference;
			}
			// 初始化后阶段, 处理 AOP 的只有 AbstractAutoProxyCreator, 但是同时可能还有其他的 BeanPostProcessor, 所以 exposedObject 和 bean 可能不是同一个对象
			// 比如 A 某个方法上有 @Async, 负责解析的是 AsyncAnnotationBeanPostProcessor, 这个类排在 AOP 之后, 执行完这个类之后, 就会产生另外一个代理对象, 与 AOP 后的代理对象不是同一个
			// 也有办法解决, 就是给 A 的 B 字段加 @Lazy, 这样 A 在注入 B 的时候直接生成代理对象, 不会产生循环依赖
			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    
    
				String[] dependentBeans = getDependentBeans(beanName);
				Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
				for (String dependentBean : dependentBeans) {
    
    
					if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
    
    
						actualDependentBeans.add(dependentBean);
					}
				}
				if (!actualDependentBeans.isEmpty()) {
    
    
					// 这里抛异常还是因为循环依赖
					// 假如A有@Async,a依赖b,b依赖a,b中注入的a是经过AOP之后的代理对象, 但是现在初始化返回的对象不是那个代理对象(参考上面的说明), 不符合单例设计了, 所以报错
					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 {
    
    
		// 和 Bean 销毁有关系, 判断 BeanDefinition 有没有定义一些销毁的逻辑, 有的则缓存起来
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	catch (BeanDefinitionValidationException ex) {
    
    
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
	}

	return exposedObject;
}

第三级缓存 singletonFactories

我们模拟的第三级缓存中(缓存1), KV 分别是 BeanName 和 原始 Bean, 但 Spring 的第三级缓存 singletonFactories 中的 KV 分别是 BeanName 和 Lambda 表达式, 即 Spring 做了更进一步的封装与设计, 该 Lambda 在发生循环依赖时的 getSingleton 方法内部执行, 从三级缓存中拿到 Lambda, 执行结果存入二级缓存

通过 Lambda 可以将 BeanName, BeanDefinition, Bean 同时传递到需要使用的地方, 还同时封装了使用方法. 在发生循环依赖的地方可以直接拿到并执行, 而不需要再找对应的 BeanName, BeanDefinition 等, 应该是会方便一些, 但并不是必须的

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    
    
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
    
    
		if (!this.singletonObjects.containsKey(beanName)) {
    
    
			this.singletonFactories.put(beanName, singletonFactory);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    
    
	Object exposedObject = bean;
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
    
		// 如果开启 AOP 的话, 这里的 BeanPostProcessor 实际生效的就是 AbstractAutoProxyCreator
		// 还有一个 InstantiationAwareBeanPostProcessorAdapter 没有逻辑, 直接返回传入的 Bean, 可以忽略
		// getEarlyBeanReference 也就是 AbstractAutoProxyCreator.getEarlyBeanReference
		for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
    
    
			exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
		}
	}
	return exposedObject;
}

AbstractAutoProxyCreator AOP 的核心类

AnnotationAwareAspectJAutoProxyCreator 是 Spring 自主注册用来处理 AOP 功能的, 其父类 AbstractAutoProxyCreator 是一个 BeanPostProcessor, AOP 功能就是该类完成的, 该类有两个方法

  • getEarlyBeanReference: 循环依赖发生时, 提前 AOP 就会执行该方法
  • postProcessAfterInitialization: 不管是否循环依赖, 初始化后阶段, 就会执行该方法
public Object getEarlyBeanReference(Object bean, String beanName) {
    
    
	Object cacheKey = getCacheKey(bean.getClass(), beanName);
	// 发生了循环依赖, 提前执行该方法, 这里标记该 Bean 会被提前执行 AOP 生成代理对象
	// 不管是否需要 AOP, 这个标记一定会存在, 只要有这个标记, 初始化后就不会执行 AOP 的相关逻辑
	/**
	 * @see AbstractAutoProxyCreator#postProcessAfterInitialization(Object, String)
	 */
	this.earlyProxyReferences.put(cacheKey, bean);
	// 执行 AOP
	return wrapIfNecessary(bean, beanName, cacheKey);
}
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    
    
	if (bean != null) {
    
    
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		// 如果该 Bean 被标记为已经提前处理过 AOP, 则这里不会再次处理
		// 未发生循环依赖的, 不会执行到 getEarlyBeanReference, 不会被标记, 所以这里会走 AOP
		/**
		 * @see AbstractAutoProxyCreator#getEarlyBeanReference(Object, String)
		 */
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    
    
			// 未执行过才执行 AOP, 返回代理对象
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	// 返回原始 Bean
	return bean;
}

这两个方法中都调用了同一个方法, wrapIfNecessary, 这个就是 AOP 的核心方法了, 细节在 AOP 中再看

其他说明

原型 Bean 情况下的循环依赖

假设ab互相依赖且ab都是原型(必须是两个都是), 这种情况下的循环依赖无法解决, 因为是原型, 并没有缓存, 会不停地创建. 但如果只有一个是原型, 则不会有问题

构造方法导致的循环依赖

假设ab互相通过构造方法依赖, 且只有一个单参构造方法(没有默认无参构造方法), 构造方法无需加@Autowired注解, 这种情况下的循环依赖无法解决. 因为Spring只能使用该构造方法来创建Bean, 实例化a时需要b, 实例化b时需要a, 因为根本无法完成实例化

可以通过加 @Lazy 的方式, 跳出循环依赖, 完成创建

@Async 情况下的循环依赖

AsyncAnnotationBeanPostProcessor 在初始化后阶段处理 @Async 注解, 生成一个新的代理对象, 将 @Async 注解标注的方法放到新线程中异步执行

为了说明 @Async, 将 doCreateBean 稍作精简如下

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

		// 实例化

		// 是否允许早期单例提前暴露, 即是否开启允许单例循环依赖
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
    
    
			// 添加三级缓存
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
		
		// 依赖注入

		// 初始化=初始化前+初始化+初始化后
		// 假如需要 AOP, 如果发生循环依赖, 初始化后不走 AOP, 返回的其实是原始对象, 而不是代理对象. 所以后面有额外的处理逻辑
		// 假如需要 AOP, 如果没有循环依赖, 初始化后要走 AOP, 返回的是代理对象
		exposedObject = initializeBean(beanName, exposedObject, mbd);

		// 如果允许早期单例提前暴露
		// 如果允许早期单例提前暴露
		if (earlySingletonExposure) {
    
    
			// allowEarlyReference=false, 即只允许到一二级缓存中查找
			Object earlySingletonReference = getSingleton(beanName, false);

			// 在二级缓存中找到了早期单例对象, 能说明以下几个情况
			// 1. 发生了循环依赖(因为只有循环依赖才会使用到二级缓存)
			// 2. AOP提前执行且初始化后阶段处理AOP的BeanPostProcessor返回的一定是原始Bean对象
			// 从缓存中取到的是早期单例对象(已经过AOP处理, 可能是代理对象也可能是原始对象)
			if (earlySingletonReference != null) {
    
    

				// 下面的判断都是基于: 初始化后阶段处理AOP的BeanPostProcessor返回的是原始Bean对象

				// 如果初始化流程返回的对象是原始对象, 说明在初始化阶段没有生成其他代理对象, 即没有其他能生成代理对象的BeanPostProcessor工作, 比如处理@Async的AsyncAnnotationBeanPostProcessor
				// 如果提前的AOP生成了代理对象, 则该对象应该作为最后的创建结果返回, 而这里初始化阶段却返回原始对象, 明显不对. 这里处理的就是这种特例情况, 将经过AOP的早期单例对象替换掉原始对象
				if (exposedObject == bean) {
    
    
					exposedObject = earlySingletonReference;
				}

				// 如果初始化流程返回的对象不是原始对象, 说明在初始化阶段有生成其他代理对象, 比如处理@Async的AsyncAnnotationBeanPostProcessor
				// 这就导致了一种可能, 其他依赖该Bean的Bean注入的是经过提前AOP处理后返回的对象(可能代理可能原始), 但这里创建出来的却是另外一个代理对象, 与单例设计不符, 所以这里要报错
				// 也有解决办法, 假设ab互相依赖且a中有一个方法有@Async注解, 此时a的创建过程会下面的错, 给a中的b加一个@Lazy注解, a直接注入一个代理的b对象, 这样不会发生循环依赖, a就能顺利创建成功 
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    
    
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
    
    
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
    
    
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
    
    
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		return exposedObject;
	}

通过上面的代码分析, 假设ab互相依赖且a内有一个@Async标注的方法(创建Bean的顺序是先a后b, 所以ab中只有a会出循环依赖问题), 此时a的创建过程会报错, 因为b注入的是a经过提前AOP后的对象(没有经过初始化后阶段的其他BeanPostProcessor处理), 而a实际创建出来的则是一个经过了初始化后阶段其他BeanPostProcessor处理过后的对象, 即两者并不是同一个对象, 违反了单例设计, 所以报错

如果给a里面的b字段加@Lazy, 可以正常运行, 因为a注入b时直接注入了b的代理对象, 然后就继续执行后续流程了, 没有发生循环依赖, 等到调用a注入的b时才会真的去找b的单例完成事实注入, 这时候才会创建b并注入其依赖的a, 而此时a早已经是一个完整的单例了, 所以可以解决报错

如果将@Async从a中移动到b中, 是否会报错? 不会, 目前有循环依赖问题的是a而不是b, a中没有了@Async后, 初始化后阶段就不会执行其对应的BeanPostProcessor, 也就不会生成新的代理对象, 因为提前AOP, 所以初始化阶段返回的对象将是原始对象, 此时会将二级缓存中的早期单例对象替换初始化阶段返回的原始对象, 能完成依赖注入且不报错. b没有循环依赖问题, b使用@Async是不会报错的

@Transactional 情况下的循环依赖

假设ab互相依赖且a内有一个@Transactional标注的方法(创建Bean的顺序是先a后b, 所以ab中只有a会出循环依赖问题), 看似和上面@Async类似, 但其实这种情况下不会报错. 因为启用异步的@AsyncEnable注解添加的是BeanPostProcessor, 而启用事务管理的@EnableTransactionManagement添加的是Advisor, 不是BeanPostProcessor, 所以在初始化阶段返回的对象并不是一个新的代理对象, 所以不会报错

自己注入自己 情况下的循环依赖

和ab互相依赖一样, 只不过会更早发现循环依赖. 假如a依赖a, 执行依赖注入, 发现需要a时a已经在创建中了, 判断出a有循环依赖问题, 提前AOP生成代理对象(如有)并完成注入, 执行初始化后判断已经执行过AOP, 返回原始对象, 然后通过后续流程从二级缓存中拿到早期代理对象, 最终加入单例池

BeanFactoryAware 下的循环依赖

没讲 …

猜你喜欢

转载自blog.csdn.net/mrathena/article/details/134315128
今日推荐