赞
踩
Spring 通过三层缓存来处理循环依赖,这些缓存分别是:
一级缓存(内存中的 singletonObjects)
二级缓存(earlySingletonObjects)
三级缓存(singletonFactories)
1. 一级缓存(singletonObjects)
这是 Spring 容器中的主要缓存区,存储已经完全初始化的单例 bean。当一个 bean 完全初始化并且所有依赖项已经注入完毕时,它会被放入这个缓存中。存储完全初始化好的单例 Bean。
2. 二级缓存(earlySingletonObjects)
这是一个存放“提前曝光”的 bean 的缓存区域。它存储的是那些已经开始实例化但还没有完成初始化的 bean。这个缓存用于解决那些在构造器注入过程中发生的循环依赖问题。存储原始的、未完全初始化的单例 Bean(提前暴露)。
3. 三级缓存(singletonFactories)
这是一个用于存储 ObjectFactory 的缓存区域,ObjectFactory 是一个工厂接口,用于创建 bean 实例。这个缓存用于在 bean 实例化过程中还未完成时提供一个工厂方法。存储原始的、带有 ObjectFactory 的单例 Bean。
例如:
- public class A {
- @Autowired
- private B b;
- }
-
- @Component
- public class B {
- @Autowired
- private A a;
- }
在这种情况下,Spring 会使用三层缓存机制来处理这两个 bean 的循环依赖。具体流程如下:
A
的过程A
的实例。它首先会在一级缓存中查找 A
,如果没有找到,再到二级缓存查找,最后到三级缓存查找。由于这是第一次创建 A
,所以在所有缓存中都找不到。A
的原始实例(但不进行依赖注入)。此时,A
的原始实例会放到三级缓存中。A
依赖 B
,于是开始创建 B
。B
的过程B
的实例。它首先会在一级缓存中查找 B
,如果没有找到,再到二级缓存查找,最后到三级缓存查找。由于这是第一次创建 B
,所以在所有缓存中都找不到。B
的原始实例(但不进行依赖注入)。此时,B
的原始实例会放到三级缓存中。B
依赖 A
。它会在一级缓存中查找 A
,没有找到;再到二级缓存中查找,还是没有找到;最后到三级缓存中查找,找到了 A
的原始实例。A
的原始实例后,Spring 将 A
注入到 B
中。B
的初始化:B
完全初始化后,Spring 将 B
的实例从三级缓存移到一级缓存。A
的初始化A
的初始化过程,Spring 将完全初始化好的 B
注入到 A
中。A
的初始化:A
完全初始化后,Spring 将 A
的实例从三级缓存移到一级缓存。AbstractAutowireCapableBeanFactory类的doCreateBean方法
- protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
- throws BeanCreationException {
-
- // Instantiate the bean.
- // 实例化 Bean
- BeanWrapper instanceWrapper = null;
- if (mbd.isSingleton()) {
- // 缓存了先前创建的 Bean 实例(如果有的话)。如果 Bean 是单例的,尝试从缓存中取出。
- instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
- }
- if (instanceWrapper == null) {
- // createBeanInstance 实际创建 Bean 实例的方法。通过反射调用构造函数或工厂方法来实例化 Bean。
- instanceWrapper = createBeanInstance(beanName, mbd, args);
- }
- // instanceWrapper:包装了 Bean 实例和类型信息。getWrappedInstance() 获取实际的 Bean 实例,getWrappedClass() 获取 Bean 的类型
- Object bean = instanceWrapper.getWrappedInstance();
- Class<?> beanType = instanceWrapper.getWrappedClass();
- if (beanType != NullBean.class) {
- mbd.resolvedTargetType = beanType;
- }
-
- // Allow post-processors to modify the merged bean definition.
- // 应用合并的 Bean 定义后处理器
- // mbd.postProcessingLock 确保在多线程环境中对 Bean 定义后处理的线程安全性。
- synchronized (mbd.postProcessingLock) {
- if (!mbd.postProcessed) {
- try {
- // 应用 Bean 定义后处理器。用于修改合并的 Bean 定义,比如处理 @PostConstruct 注解的方法
- applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
- }
- catch (Throwable ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "Post-processing of merged bean definition failed", ex);
- }
- mbd.postProcessed = true;
- }
- }
-
- // Eagerly cache singletons to be able to resolve circular references
- // even when triggered by lifecycle interfaces like BeanFactoryAware.
- // 提前缓存单例以解决循环依赖
- boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
- isSingletonCurrentlyInCreation(beanName)); // 如果 Bean 是单例的,并且允许循环依赖,且当前正在创建这个单例 Bean,则允许提前缓存
- if (earlySingletonExposure) {
- if (logger.isTraceEnabled()) {
- logger.trace("Eagerly caching bean '" + beanName +
- "' to allow for resolving potential circular references");
- }
- // addSingletonFactory:将一个 ObjectFactory 放入三级缓存,以便在 Bean 完全初始化后获取实例。这个 ObjectFactory 会在稍后阶段调用 getEarlyBeanReference 来获取 Bean 实例。
- addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
- }
-
- // Initialize the bean instance.
- // 填充 Bean 属性和初始化 Bean
- Object exposedObject = bean;
- try {
- // populateBean:填充 Bean 的属性
- populateBean(beanName, mbd, instanceWrapper);
- // initializeBean:初始化 Bean,比如执行 @PostConstruct 注解的方法,或者其他初始化逻辑
- 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) {
- // getSingleton(beanName, false):尝试从一级缓存中获取 Bean 实例。如果 Bean 尚未完全初始化,它会从三级缓存中获取到
- Object earlySingletonReference = getSingleton(beanName, false);
- if (earlySingletonReference != null) {
- if (exposedObject == bean) {
- exposedObject = earlySingletonReference;
- }
- // hasDependentBean(beanName):检查是否有其他 Bean 依赖于当前 Bean
- else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
- String[] dependentBeans = getDependentBeans(beanName);
- Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
- for (String dependentBean : dependentBeans) {
- // removeSingletonIfCreatedForTypeCheckOnly(dependentBean):移除仅用于类型检查的 Bean。
- if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
- actualDependentBeans.add(dependentBean);
- }
- }
- if (!actualDependentBeans.isEmpty()) {
- // BeanCurrentlyInCreationException:如果发现有依赖于当前 Bean 的其他 Bean,这个异常会被抛出,提示 Bean 已被提前注入而且存在循环依赖
- 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.
- // 注册 Bean 为可销毁的
- try {
- // registerDisposableBeanIfNecessary:注册 Bean 的销毁回调方法(如果有的话),以便在容器销毁时调用
- registerDisposableBeanIfNecessary(beanName, bean, mbd);
- }
- catch (BeanDefinitionValidationException ex) {
- throw new BeanCreationException(
- mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
- }
- // 返回 Bean 实例
- return exposedObject;
- }
关键点
- // 提前缓存单例以解决循环依赖
- boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
- isSingletonCurrentlyInCreation(beanName)); // 如果 Bean 是单例的,并且允许循环依赖,且当前正在创建这个单例 Bean,则允许提前缓存
- if (earlySingletonExposure) {
- if (logger.isTraceEnabled()) {
- logger.trace("Eagerly caching bean '" + beanName +
- "' to allow for resolving potential circular references");
- }
- // addSingletonFactory:将一个 ObjectFactory 放入三级缓存,以便在 Bean 完全初始化后获取实例。这个 ObjectFactory 会在稍后阶段调用 getEarlyBeanReference 来获取 Bean 实例。
- addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
- }
一级缓存(内存中的 singletonObjects)
二级缓存(earlySingletonObjects)
三级缓存(singletonFactories)
- // 检查并处理循环依赖
- if (earlySingletonExposure) {
- // getSingleton(beanName, false):尝试从一二级缓存中获取 Bean 实例。如果 Bean 尚未完全初始化,它会从三级缓存中获取到
- Object earlySingletonReference = getSingleton(beanName, false);
- if (earlySingletonReference != null) {
- if (exposedObject == bean) {
- exposedObject = earlySingletonReference;
- }
- // hasDependentBean(beanName):检查是否有其他 Bean 依赖于当前 Bean
- else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
- String[] dependentBeans = getDependentBeans(beanName);
- Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
- for (String dependentBean : dependentBeans) {
- // removeSingletonIfCreatedForTypeCheckOnly(dependentBean):移除仅用于类型检查的 Bean。
- if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
- actualDependentBeans.add(dependentBean);
- }
- }
- if (!actualDependentBeans.isEmpty()) {
- // BeanCurrentlyInCreationException:如果发现有依赖于当前 Bean 的其他 Bean,这个异常会被抛出,提示 Bean 已被提前注入而且存在循环依赖
- 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.");
- }
- }
- }
- }
构造函数循环依赖:
- @Component
- public class A {
- private B b;
-
- @Autowired
- public A(B b) {
- this.b = b;
- }
- }
-
- @Component
- public class B {
- private A a;
-
- @Autowired
- public B(A a) {
- this.a = a;
- }
- }
Bean 的作用域(Scope):
spring bean的作用域:
Singleton(单例),Prototype(多例),Request(请求),Session(会话),Application(应用)
自定义 Bean 后处理器(BeanPostProcessor):
BeanPostProcessor
中存在某些逻辑,导致提前访问 Bean 的实例,可能会打破三级缓存的逻辑,导致循环依赖异常。@Autowired
注解处理器或其他涉及提前引用 Bean 的处理器,可能导致 Bean 被提前实例化,从而引发循环依赖异常。FactoryBean 的复杂依赖:
FactoryBean
的复杂依赖关系可能导致 Spring 在创建 Bean 实例时遇到困难,从而引发循环依赖异常。AOP 动态代理:
@Lazy
注解--懒加载使用 @Lazy
注解可以推迟 Bean 的初始化,直到真正需要该 Bean 时才进行初始化。这样可以打破循环依赖链。
@PostConstruct
注解使用 @PostConstruct
注解在 Bean 初始化之后执行某些操作,这样可以将依赖的初始化推迟到 Bean 完全创建之后。
如:构造函数注入+ ObjectFactory; @Autowired
注解放在字段上; 使用 Setter 方法注入依赖
@Autowired
srping自动处理成功启动
启动出现循环依赖
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。