spring 源码解析之 doGetBean

前言

经过了前一章的分析(spring 源码解析之 bean 的获取),我们是对 bean 的获取过程有了大致的了解,接下来就是详细剖析每个方法。以及为什么要这样做。

源码解析

transformedBeanName

根据 name获取 beanName,这里的 name 跟 beanName 有什么区别呢,这个 name 可能是普通的 bean名称,也可能是 factoryBean这个特殊的bean名称,factoryBean的名称是带有&的,所以要去掉特殊的符号。

getSingleton

前面已经提到过,单例在Spring 的同一个容器内只会被创建一次,后续再获取 bean 直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试从 singletonFactories 中加载。因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring 创建bean的原则是不等bean 创建完成就会将创建bean 的 ObjectFactory 提早曝光加人到缓存中,一旦下一个 bean 创建时需要依赖上个 bean,则直接使用 ObjectFactory。这里好多概念如循环依赖、单例缓存、提早曝光等,后面会一一讲清楚,不着急,先混个眼熟。

  • 优先从singletonObjects这个缓存中获取,如果存在则直接返回,
  • 如果不存在则判断该 bean是否正在创建,如果是,则从earlySingletonObjects获取,返回
  • 如果还获取不到,则判断是否运行循环依赖,允许则在singletonFactories这个缓存中获取,返回
  • 如果再获取不到,那就返回 null。
java 复制代码
 @Nullable
 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    // 获取单例 bean
    Object singletonObject = this.singletonObjects.get(beanName);
    // 如果bean 不在缓存中,并且当前正在创建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
       // 获取早期曝光的 bean (二级缓存里的 bean)
       singletonObject = this.earlySingletonObjects.get(beanName);
       // allowEarlyReference 是否可以循环依赖
       if (singletonObject == null && allowEarlyReference) {
          // 因为所有的 bean 缓存都是全局的,因此需要在锁内检查一次
          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) {
                      singletonObject = singletonFactory.getObject();
                      this.earlySingletonObjects.put(beanName, singletonObject);
                      this.singletonFactories.remove(beanName);
                   }
                }
             }
          }
       }
    }
    return singletonObject;
 }

这里最主要的就是这几个缓存是什么东西?这三个缓存就是用来解决循坏依赖的问题,这也是面试会经常被问到的问题。

java 复制代码
 // singleton对象的缓存:bean名称到bean实例
 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
 ​
 /** Cache of singleton factories: bean name to ObjectFactory. */
 // 单例工厂缓存:bean名称到ObjectFactory HashMap。这是为了解决循环依赖问题,用于提前暴露对象 (三级缓存)
 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
 ​
 /** Cache of early singleton objects: bean name to bean instance. */
 // 早期曝光的singleton对象的缓存:bean名称到bean实例 (二级缓存)
 private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
   /** Names of beans that are currently in creation. */
   // 当前正在创建的bean的名称
 private final Set<String> singletonsCurrentlyInCreation =
       Collections.newSetFromMap(new ConcurrentHashMap<>(16));

这里有一个问题了,什么是循坏依赖,什么是早期曝光的 bean?下面是简单解释一下,详细了解看一下这篇文章:spring 源码解析番外篇之什么是循环依赖

java 复制代码
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 ​
 @Component
 public class BeanA {
     private final BeanB beanB;
 ​
     // A依赖 B
     @Autowired
     public BeanA(BeanB beanB) {
         this.beanB = beanB;
     }
 }
 ​
 @Component
 public class BeanB {
     private final BeanA beanA;
 ​
     // B 依赖 A
     @Autowired
     public BeanB(BeanA beanA) {
         this.beanA = beanA;
     }
 }
 ​
  • 上面的例子就是循坏依赖的例子,如果先是BeanA先实例化,则会查找该 bean 的依赖 bean。查到依赖 BeanB之后,先将BeanA 暂停实例化,同时会将 BeanA的引用ObjectFactory缓存到singletonFactories之中,然后就会优先将 BeanB 实例化完,再对 BeanA 继续实例化。

  • 由于 BeanA 暂停实例化了,优先 BeanB 进行实例化,那么重复上面的步骤,BeanB 会找到 BeanA 的依赖,又优先实例化 BeanA,如此就会进入一个死循环,所以为了解决这个问题,spring 就创建了上面那三个缓存

  • 当实例化BeanB时,查询 BeanA 依赖同样会优先尝试从 singletonObjects 里面获取实例,如果获取不到再从 earlySingletonObjects 里面获取,如果还获取不到,再尝试从 ingletonFactories 里面获取 beanName 对应的ObjectFactory,然后调用这个 ObjectFactory 的 getObject 来创建 bean,并放到 earlySingletonObjects 里面去,并且从 singletonFactories 里面 remove 掉这个 ObjectFactory。此时earlySingletonObjects中的 BeanA 就是早期曝光的 bean

  • 而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在 allowEarlyReference 为 true 的情况下才会使用。

  • 这里涉及用于存储bean 的不同的 map,一开始可能很难理解,这也是所谓的三级缓存,用来处理循环依赖问题。

    • singletonObjects:用于保存 BeanName和创建bean 实例之间的关系,bean name --> bean instance(一级缓存
    • earlySingletonObjects:也是保存 BeanName 和创建 bean 实例之间的关系,与singletonObjects 的不同之处在于,当一个单例bean 被放到这里面后,那么当 bean 还在创建过程中,就可以通过 getBean 方法获取到了,其目的是用来检测循环引用 (二级缓存
    • singletonFactories:用于保存 BeanName 和创建 bean的工厂之间的关系,bean name --> ObjectFactory (三级缓存
    • registeredSingletons:用来保存当前所有已注册的bean。

getObjectForBeanInstance

AbstractBeanFactory#getObjectFromFactoryBean根据方法名称可以知道,这个方法就是返回bean 实例对象的。我们无论是从缓存中获取到的 bean 还是通过不同的 scope 策略加载的 bean 都只是最原始的 bean 状态,并不一定是我们最终想要的 bean。举个例子,假如我们需要对工厂的 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean,而getObjectForBeanInstance就是完成这个工作的。

java 复制代码
 /**
    * 获取给定bean实例的对象,在FactoryBean的情况下,可以是bean实例本身,也可以是其创建的对象。这个话会有解释
    */
   protected Object getObjectForBeanInstance(
       Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
 ​
     // Don't let calling code try to dereference the factory if the bean isn't a factory.
     // 判断name是否是FactoryBean的 name
     if (BeanFactoryUtils.isFactoryDereference(name)) {
       if (beanInstance instanceof NullBean) {
         return beanInstance;
       }
       // 以&开头又不是FactoryBean实现类,则抛出异常
       if (!(beanInstance instanceof FactoryBean)) {
         throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
       }
       if (mbd != null) {
         mbd.isFactoryBean = true;
       }
       return beanInstance;
     }
 ​
     // Now we have the bean instance, which may be a normal bean or a FactoryBean.
     // If it's a FactoryBean, we use it to create a bean instance, unless the
     // caller actually wants a reference to the factory.
     // 此时bean可能是 FactoryBean 或者 普通的bean。
     // 判断如果 beanInstance 不是 FactoryBean而是普通的bean, 就直接返回
     if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
       return beanInstance;
     }
 ​
     // 到这一步就可以确定,当前beanInstance 是FactoryBean,并且需要获取getObject() 的结果
     Object object = null;
     if (mbd != null) {
       mbd.isFactoryBean = true;
     }
     else {
       // 尝试从缓存中加载bean。这一步是从 factoryBeanObjectCache 集合中获取
       // 在后面获取 bean 成功后,可能会将 其缓存到 factoryBeanObjectCache  中
       object = getCachedObjectForFactoryBean(beanName);
     }
     if (object == null) {
       // Return bean instance from factory.
       // Caches object obtained from FactoryBean if it is a singleton.
       // containsBeanDefinition 检测  beanDefinitionMap中也就是所有已经加载的类中检测是否定义beanName
       if (mbd == null && containsBeanDefinition(beanName)) {
         // 如果存在 则合并父类 bean 定义的属性
         mbd = getMergedLocalBeanDefinition(beanName);
       }
       boolean synthetic = (mbd != null && mbd.isSynthetic());
       // 这一步中对FactoryBean进行了解析。
       object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic);
     }
     return object;
   }

获取给定bean实例的对象,在FactoryBean的情况下,可以是bean实例本身,也可以是其创建的对象。这句话怎么理解呢?比如下面这个例子

java 复制代码
 ​
 public class MyFactoryBean implements FactoryBean<MyObject> {
 ​
     @Override
     public MyObject getObject() throws Exception {
         // 这里创建并返回MyObject实例
         return new MyObject();
     }
 ​
     @Override
     public Class<?> getObjectType() {
         return MyObject.class;
     }
 ​
     @Override
     public boolean isSingleton() {
         return true;
     }
 }
 ​
 // 简单写个方法
 MyObject myObject = (MyObject) context.getBean("myFactoryBean");
 MyFactoryBean myFactoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");
 ​
  • 这也就为什么在一开始会有特殊字符处理,所以这个方法一开始在判断是否是FactoryBean
  • 如果不是FactoryBean那就是普通的 bean 实例,直接返回
  • 如果是FactoryBean,则使用这个FactoryBean创建 bean 实例
  • 调用getObjectFromFactoryBean获取 bean 实例

从上述的代码来看,其实这个方法没有什么重要的信息,大多是辅助代码以及一些功能性判断,而真正的核心代码委托给了FactoryBeanRegistrySupport#getObjectFromFactoryBean,我们一起来看看。

getObjectFromFactoryBean

java 复制代码
 protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 判断是否是单例并且是否已经缓存过了
    if (factory.isSingleton() && containsSingleton(beanName)) {
       synchronized (getSingletonMutex()) {
          // 获取缓存的单例对象
          Object object = this.factoryBeanObjectCache.get(beanName);
          if (object == null) {
             // 在这个方法中进行解析。调用 FactoryBean 的 getObject 方法。factory.getObject()
             object = doGetObjectFromFactoryBean(factory, beanName);
             // Only post-process and store if not put there already during getObject() call above
             // (e.g. because of circular reference processing triggered by custom getBean calls)
             // 因为是单例模式,所以要保证变量的全局唯一。所以这里如果缓存中已经创建好了bean则替换为已经创建好的bean
             Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
             if (alreadyThere != null) {
                object = alreadyThere;
             }
             else {
                // // 如果允许调用bean的后置处理器。因为这里是直接将bean创建返回了,如果要调用后置方法则只能在这里调用。
                if (shouldPostProcess) {
                   if (isSingletonCurrentlyInCreation(beanName)) {
                      // Temporarily return non-post-processed object, not storing it yet..
                      return object;
                   }
                   // 将beanName 添加到 singletonsCurrentlyInCreation 中缓存,表示当前bean正在创建中
                   beforeSingletonCreation(beanName);
                   try {
                      object = postProcessObjectFromFactoryBean(object, beanName);
                   }
                   catch (Throwable ex) {
                      throw new BeanCreationException(beanName,
                            "Post-processing of FactoryBean's singleton object failed", ex);
                   }
                   finally {
                      // 将beanName 从 singletonsCurrentlyInCreation 中移除,表示当前bean已经创建结束
                      afterSingletonCreation(beanName);
                   }
                }
                // 添加到factoryBeanObjectCache缓存中
                if (containsSingleton(beanName)) {
                   // 这里保存的是 beanName : FactoryBean
                   this.factoryBeanObjectCache.put(beanName, object);
                }
             }
          }
          return object;
       }
    }
    else {
       Object object = doGetObjectFromFactoryBean(factory, beanName);
       if (shouldPostProcess) {
          try {
             object = postProcessObjectFromFactoryBean(object, beanName);
          }
          catch (Throwable ex) {
             throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
          }
       }
       return object;
    }
 }

如果是单例并且在singletonObjects这个缓存中已经缓存过的,非单例获取未缓存过的直接使用doGetObjectFromFactoryBean,并调用后置处理器postProcessObjectFromFactoryBean

  • 先尝试在factoryBeanObjectCache这个缓存中获取,如未缓存
  • 则再从doGetObjectFromFactoryBean此方法使用factory.getObject()获取
  • 如果允许调用后置处理器,则调用postProcessObjectFromFactoryBean
  • 添加factoryBeanObjectCache缓存

我当时看到这里就有个疑问,为什么要先判断singletonObjects是否已经缓存了?那如果已经缓存了,为什么不直接使用这个 bean 实例呢?

  • singletonObjects这个缓存中存在对应的 bean,那么就意味着这个Bean已经被实例化过了。这并不意味着我们可以直接从singletonObjects缓存中获取Bean的实例对象。因为这里的 bean 只是一个原始的 bean 实例,也就是在这个方法解析之前所说,我们从缓存获取到的实例对象并不是最终状态的 bean 对象
  • 因为在Spring中,一个Bean的创建过程可能会涉及到一些后处理操作,这些操作可能会改变Bean的最终状态。这就是为什么我们需要尝试从factoryBeanObjectCache这个缓存中获取Bean的原因
  • factoryBeanObjectCache缓存中存储的是已经经过后处理的Bean实例。当我们调用getObjectFromFactoryBean方法时,如果beanName已经存在于singletonObjects缓存中,那么我们会尝试从factoryBeanObjectCache缓存中获取已经经过后处理的Bean实例。如果在factoryBeanObjectCache缓存中找不到,那么我们会执行后处理操作,然后将处理后的Bean实例存入factoryBeanObjectCache缓存
  • 这样做的好处是,我们可以确保无论何时获取Bean,都能获取到的是已经经过后处理的Bean实例,而不仅仅是原始的、未经处理的Bean实例。这对于保证Spring框架的稳定性和可预测性是非常重要的。

doGetObjectFromFactoryBean

经过上面的代码,还是没有看到有关键的信息,重要的操作委托给了FactoryBeanRegistrySupport#doGetObjectFromFactoryBean

而重要的代码就是这一行object = factory.getObject();

java 复制代码
 private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
    Object object;
    try {
       object = factory.getObject();
    }
     ......
    return object;
 }

上面我们已经讲述了 FactoryBean 的调用方法,如果 bean 声明为 FactoryBean 类型,则当提取 bean 时提取的并不是 FactoryBean,而是 FactoryBean 中对应的getObject 方法返回的 bean,而 doGetObjectFromFactoryBean 正是实现这个功能的。但是,我们看到在上面的方法中除了调用 object = factory.getObject()得到我们想要的结果后并没有直接返回,而是接下来又做了些后处理的操作,回到getObjectFromFactoryBean继续跟踪进入 AbstractAutowireCapableBeanFactory类的 postProcessObjectFromFactoryBean 方法。

java 复制代码
 @Override
 protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
    return applyBeanPostProcessorsAfterInitialization(object, beanName);
 }
 ​
 @Override
 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
     throws BeansException {
 ​
   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
     Object current = processor.postProcessAfterInitialization(result, beanName);
     if (current == null) {
       return result;
     }
     result = current;
   }
   return result;
 }
  • 对于后处理器的使用还未过多接触,后续会详细介绍,这里,我们只需了解在 Spring获取 bean 的规则中有这样一条:尽可能保证所有bean 初始化后都会调用注册的BeanPostProcessor 的 postProcessAfterInitialization 方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。

getParentBeanFactory

回到doGetBean方法,接下来解析getParentBeanFactory。如果存在父级工厂,并当前的BeanDefinition不存在,则尝试去父级工厂获取

java 复制代码
 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    // Not found -> check parent.
    // 递归到BeanFactory中检测
    String nameToLookup = originalBeanName(name);
    if (parentBeanFactory instanceof AbstractBeanFactory abf) {
       return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
    }
    else if (args != null) {
       // Delegation to parent with explicit args.
       return (T) parentBeanFactory.getBean(nameToLookup, args);
    }
    else if (requiredType != null) {
       // No args -> delegate to standard getBean method.
       return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
    else {
       return (T) parentBeanFactory.getBean(nameToLookup);
    }
 }

getMergedLocalBeanDefinition

将当前的BeanDefinition与父级的BeanDefinition 合并成一个BeanDefinition,RootBeanDefinition:mdb,后面基本都是使用这个参数,一路点点点点下去,最终会来到AbstractBeanFactory#getMergedBeanDefinition

java 复制代码
 protected RootBeanDefinition getMergedBeanDefinition(
       String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
       throws BeanDefinitionStoreException {
 ​
    synchronized (this.mergedBeanDefinitions) {
       RootBeanDefinition mbd = null;
       RootBeanDefinition previous = null;
 ​
       // Check with full lock now in order to enforce the same merged instance.
       if (containingBd == null) {
          mbd = this.mergedBeanDefinitions.get(beanName);
       }
 ​
       if (mbd == null || mbd.stale) {
          previous = mbd;
          // 判断如果parentName为空则没必要进行合并了,直接克隆返回即可
          if (bd.getParentName() == null) {
             // Use copy of given root bean definition.
             if (bd instanceof RootBeanDefinition rootBeanDef) {
                mbd = rootBeanDef.cloneBeanDefinition();
             }
             else {
                mbd = new RootBeanDefinition(bd);
             }
          }
          else {
             // Child bean definition: needs to be merged with parent.
             BeanDefinition pbd;
             try {
                String parentBeanName = transformedBeanName(bd.getParentName());
                // 递归调用,解析更上层的parent BeanDefinition ,直到beanName=parentBeanName或者parentBeanName为 null
                if (!beanName.equals(parentBeanName)) {
                   pbd = getMergedBeanDefinition(parentBeanName);
                }
                else {
                   // 获取父bean的beanDefinition
                   if (getParentBeanFactory() instanceof ConfigurableBeanFactory parent) {
                      pbd = parent.getMergedBeanDefinition(parentBeanName);
                   }
                   else {
                      throw new NoSuchBeanDefinitionException(parentBeanName,
                            "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                  "': cannot be resolved without a ConfigurableBeanFactory parent");
                   }
                }
             }
             catch (NoSuchBeanDefinitionException ex) {
                throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                      "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
             }
             // Deep copy with overridden values.
             // 深拷贝
             mbd = new RootBeanDefinition(pbd);
             mbd.overrideFrom(bd);
          }
 ​
          // Set default singleton scope, if not configured before.
          if (!StringUtils.hasLength(mbd.getScope())) {
             mbd.setScope(SCOPE_SINGLETON);
          }
 ​
          // A bean contained in a non-singleton bean cannot be a singleton itself.
          // Let's correct this on the fly here, since this might be the result of
          // parent-child merging for the outer bean, in which case the original inner bean
          // definition will not have inherited the merged outer bean's singleton status.
          if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
             mbd.setScope(containingBd.getScope());
          }
 ​
          // Cache the merged bean definition for the time being
          // (it might still get re-merged later on in order to pick up metadata changes)
          if (containingBd == null && isCacheBeanMetadata()) {
             this.mergedBeanDefinitions.put(beanName, mbd);
          }
       }
       if (previous != null) {
          copyRelevantMergedBeanDefinitionCaches(previous, mbd);
       }
       return mbd;
    }
 }
  • 使用BeanDefinition获取parentName,判断如果parentName为空则没必要进行合并了,直接克隆返回即可
  • 如果存在父类的 bean,递归调用,解析更上层的parent BeanDefinition ,直到beanName=parentBeanName或者parentBeanName为 null
  • 获取父bean的beanDefinition#pbd,然后深拷贝到RootBeanDefinition#mdb
  • 添加缓存mergedBeanDefinitions

查询依赖 bean

原本以为这个方法很简单,但是当初详细深入进去,有几个地方有疑问的,带我一一剖析。

先直接看到源码中的isDependent这个方法。DefaultSingletonBeanRegistry#isDependent

java 复制代码
 private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
    // 是否已经检测过了
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
       return false;
    }
    // 从aliasMap中获取别名映射的 beanName
    String canonicalName = canonicalName(beanName);
    // 获取依赖的beanName
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    if (dependentBeans == null || dependentBeans.isEmpty()) {
       return false;
    }
    // 如果 依赖于 beanName中存在 dependentBeanName 则说明存在循环依赖。
    // 代码走到这里说明是beanName 创建过程中要依赖 dependentBeanName。但是dependentBeans.contains(dependentBeanName) = true 则说明dependentBeanName依赖于beanName
    // 造成了 A依赖B,B依赖A的情况
    if (dependentBeans.contains(dependentBeanName)) {
       return true;
    }
    // 递归,确定没有A->B->C-A 这种长链路的循环依赖情况
    if (alreadySeen == null) {
       alreadySeen = new HashSet<>();
    }
    alreadySeen.add(beanName);
    for (String transitiveDependency : dependentBeans) {
       if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
          return true;
       }
    }
    return false;
 }

当时我的疑问? 问题1、为什么dependentBeans.contains(dependentBeanName)如果存在这个依赖就直接抛异常?(isDependent这个方法返回true,则 doGetCreate 方法就抛异常)

这里涉及到两个缓存dependentBeanMap、dependenciesForBeanMap,这两个缓存主要用于存储和管理Bean之间的依赖关系,但是作用一个是依赖的 bean 作为 key,一个是被依赖的作为 key。

如果一个 BeanA 使用 @Autowired 注入了 BeanB,那么在这两个缓存中的存储方式如下:

  • dependentBeanMap:在这个缓存中,BeanB 作为键,BeanA 作为值。这是因为 BeanA 依赖于 BeanB,所以 BeanB 被 BeanA 所依赖。
  • dependenciesForBeanMap:在这个缓存中,BeanA 作为键,BeanB 作为值。这是因为 BeanA 依赖于 BeanB,所以 BeanA 有一个依赖,即 BeanB。

所以一开始就确定beanName依赖于dependentBeanName,所以这里使用dependentBeanMap判断两者是否存在循坏依赖,如果存在,则直接抛异常

问题 2、为什么循坏依赖直接抛异常,不是有三级缓存吗?

这里有涉及到一个问题,mbd.getDependsOn();获取的并非是依赖注入(使用@Autowired)的依赖 bean,而是depends-on中的 bean,下面的beanA则依赖于beanB,但是beanB 并非直接注入到 beanA 中,而是要确定beanB的初始化必须要在beanA 之前

所以@Autowired是直接依赖注入,depends-on(@DependsOn)则是定义 bean 的初始化循序。

xml 复制代码
 <beans>
     <bean id="beanA" class="ExampleBean" depends-on="beanB">
         <property name="manager" ref="manager" />
     </bean>
     <bean id="beanB" class="BeanB" />
 </beans>
 ​

所以如果出现循坏依赖时,即 BeanA 与 BeanB 相互依赖,但是BeanA 又使用了@DependsOn依赖 BeanB,那么在初始化 BeanA 时,发现BeanB 要初始化完成在 BeanA 之前,但是 BeanB 又要依赖 BeanA,就会相互冲突,所以 spring 对此会直接抛异常。

注: @DependsOn:注解是在另外一个实例创建之后才创建当前实例,也就是,最终两个实例都会创建,只是顺序不一样 @ConditionalOnBean :注解是只有当另外一个实例存在时,才创建,否则不创建,也就是,最终有可能两个实例都创建了,有可能只创建了一个实例,也有可能一个实例都没创建

相关推荐
2501_9061505614 分钟前
私有部署问卷系统操作实战记录-DWSurvey
java·运维·服务器·spring·开源
better_liang26 分钟前
每日Java面试场景题知识点之-TCP/IP协议栈与Socket编程
java·tcp/ip·计算机网络·网络编程·socket·面试题
niucloud-admin38 分钟前
java服务端——controller控制器
java·开发语言
To Be Clean Coder39 分钟前
【Spring源码】通过 Bean 工厂获取 Bean 的过程
java·后端·spring
Fortunate Chen1 小时前
类与对象(下)
java·javascript·jvm
程序员水自流1 小时前
【AI大模型第9集】Function Calling,让AI大模型连接外部世界
java·人工智能·llm
‿hhh1 小时前
综合交通运行协调与应急指挥平台项目说明
java·ajax·npm·json·需求分析·个人开发·规格说明书
小徐Chao努力1 小时前
【Langchain4j-Java AI开发】06-工具与函数调用
java·人工智能·python
无心水1 小时前
【神经风格迁移:全链路压测】33、全链路监控与性能优化最佳实践:Java+Python+AI系统稳定性保障的终极武器
java·python·性能优化
萧曵 丶1 小时前
Synchronized 详解及 JDK 版本优化
java·多线程·synchronized