likes
comments
collection
share

spring 源码解析之 createBean

作者站长头像
站长
· 阅读数 2

前言

源码解析

getSingleton

 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
       // 获取单例 bean
       Object singletonObject = this.singletonObjects.get(beanName);
       // bean 实例为空,则创建单例bean
       if (singletonObject == null) {
          // 判断,如果当前beanFactory正在被销毁则直接抛出异常,不允许创建单例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!)");
          }
          if (logger.isDebugEnabled()) {
             logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
          }
          // 做一些bean创建前的准备工作: 记录beanName 正在加载的状态(添加到 singletonsCurrentlyInCreation 缓存中),
          // 若bean已经正在加载,则抛出异常。为了解决循环引用的问题
          beforeSingletonCreation(beanName);
          boolean newSingleton = false;
          boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
          if (recordSuppressedExceptions) {
             this.suppressedExceptions = new LinkedHashSet<>();
          }
          try {
             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;
             }
             // 从singletonsCurrentlyInCreation删除正在记录创建中的beanName
             afterSingletonCreation(beanName);
          }
          // 添加到singletonObjects缓存中 从二级缓存 三级缓存中移除
          if (newSingleton) {
             addSingleton(beanName, singletonObject);
          }
       }
       return singletonObject;
    }
 }
  • this.singletonObjects.get(beanName) :再次尝试从缓存中获取bean,若获取到,就大吉大利直接返回。若为空,则需要创建 bean。
  • if (this.singletonsCurrentlyInDestruction) :未获取到检测bena是否正在销毁,若是则抛出异常
  • beforeSingletonCreation 方法中记录bean正在创建的状态将beanName添加到singletonsCurrentlyInCreation集合中)。在循环依赖时可根据此判断。
  • singletonObject = singletonFactory.getObject() :调用 ObjectFactory.getObject() 方法来实例化bean
  • afterSingletonCreation 方法移除bean正在夹杂的状态
  • addSingleton(beanName, singletonObject): 对各种缓存状态做处理。

beforeSingletonCreation

这个方法并非一个空方法,重点是!this.singletonsCurrentlyInCreation.add(beanName), 记录beanName 正在加载的状态(添加到 singletonsCurrentlyInCreation 缓存中)

 protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
       throw new BeanCurrentlyInCreationException(beanName);
    }
 }

创建bean - createBean概述

这个方法这行代码才是重头:singletonObject = singletonFactory.getObject();这一行代码实则就是调用doGetBean下的 createBean

spring 源码解析之 createBean

createBean是根据给定的bean名称(beanName)和根bean定义(RootBeanDefinition对象mbd)创建并初始化一个Bean实例,上面一系列的操作都是创建bean 做准备工作的。现在开始真正来创建 bean 了,下面看源码

 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
       throws BeanCreationException {
 ​
    if (logger.isTraceEnabled()) {
       logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;
 ​
    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    // 1. 锁定class, 根据mdb和 beanName 解析出来 bean的class类型
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
       mbdToUse = new RootBeanDefinition(mbd);
       mbdToUse.setBeanClass(resolvedClass);
    }
 ​
    // Prepare method overrides.
    try {
       // 此方法的主要作用是验证和准备Bean的方法重写。
       // 这个方法会遍历Bean的所有方法,如果一个方法只被重载了一次,那么就设置overloaded为false,以避免参数类型的检查。因为这个检查很耗性能
       // 这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配了。此外,这个方法还可以提前对方法存在性进行验证。
       // 为了优化方法的调用,提高程序的运行效率。
       mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
       throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
             beanName, "Validation of method overrides failed", ex);
    }
 ​
    try {
       // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
       // 调用BeanProcessors的方法来替代真正的实例
       // 给BeanPostProcessors一个返回代理而不是目标bean实例的机会
       // 如果处理器返回了代理,那么就直接返回代理,不再进行后续的初始化操作。
       // 这个方法可以让用户使用处理器来创建 bean 实例,不通过 spring 来创建 bean 实例。
       //InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation : 在bean初始化前调用
       //BeanPostProcessor#postProcessAfterInitialization : 在bean初始化后调用
       Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
       if (bean != null) {
          return bean;
       }
    }
    catch (Throwable ex) {
       throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
             "BeanPostProcessor before instantiation of bean failed", ex);
    }
 ​
    try {
       Object beanInstance = doCreateBean(beanName, mbdToUse, args);
       if (logger.isTraceEnabled()) {
          logger.trace("Finished creating instance of bean '" + beanName + "'");
       }
       return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
       // A previously detected exception with proper bean creation context already,
       // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
       throw ex;
    }
    catch (Throwable ex) {
       throw new BeanCreationException(
             mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
 }

可以看到,createBean 的整体流程大致如下:

  1. 解析并锁定Bean Class:确保在这一阶段解析出实际的Bean类,并在需要时克隆mbd以存储动态解析得到的Class(由于某些原因无法存储在共享合并的bean定义中)。具体做法是调用resolveBeanClass(mbd, beanName)方法。

    • resolveBeanClass(mbd, beanName)方法用于根据给定的RootBeanDefinition (mbd) 和 beanName 来获取实际的Bean类(即Java Class对象)
    • 判断条件resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null表示:
      • resolvedClass != null: 确保已经成功解析出一个Class对象。
      • !mbd.hasBeanClass(): 检查当前的RootBeanDefinition是否已经包含了一个已知的Class引用(例如,它可能是从XML或注解配置中读取的)。
      • mbd.getBeanClassName() != null: 确认RootBeanDefinition中包含了可用于查找类名的字符串信息。
      • 如果满足这些条件,则创建一个新的RootBeanDefinition实例(mbdToUse),将原始mbd的其他属性复制过来,并使用刚解析得到的Class对象(resolvedClass)来设置新的Bean定义的Class属性
    • 这样做的原因在于,原始的RootBeanDefinition可能存储的是一个类名字符串而不是Class对象本身,而在后续处理过程中,有时需要直接操作Class对象进行更高效的操作,比如反射调用、生成代理类等。
  2. 准备方法重写:通过调用mbdToUse.prepareMethodOverrides()来验证和准备Bean的方法重写。这个过程会遍历Bean的所有方法,优化后续对方法的调用,提高运行效率,同时提前进行方法存在性验证。

  3. 应用BeanPostProcessor:在真正实例化Bean之前,提供一个机会让注册的InstantiationAwareBeanPostProcessorBeanPostProcessor通过resolveBeforeInstantiation(beanName, mbdToUse)方法返回代理对象替代目标Bean实例。如果处理器返回了非空代理对象,则直接返回该代理对象,不再继续执行后续的Bean初始化流程。

  4. 创建并初始化Bean实例:如果没有BeanPostProcessor返回代理对象或者返回的对象为空,函数将调用doCreateBean(beanName, mbdToUse, args)方法来实际地创建并初始化Bean实例。此方法内部包含了依赖注入、属性填充以及调用初始化方法等一系列操作。

  5. 异常处理:在整个创建过程中,函数会捕获并处理可能出现的任何异常,包括但不限于BeanCreationExceptionImplicitlyAppearedSingletonException。若出现异常,函数会抛出相应的异常信息,其中包含有关异常发生的上下文,以便于调试定位问题。 最终,当Bean实例成功创建并初始化完成后,函数返回该Bean实例。

prepareMethodOverrides

这里我又理解了好久,主要一开始看到这里说的方法重写就想到了方法重载与重写的那个,其实这里所说的是不一样的。

这里主要是理解lookup-methodreplaced-method 两个属性与@Override这玩意是不一样的。

总的来说,@Override是在编译时确定的,它要求子类的方法必须与父类的方法完全相同。而Spring的lookup-method和replace-method是在运行时确定的,它们可以动态地改变方法的行为。

看一下源码

 public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    // Check that lookup methods exist and determine their overloaded status.
    // 判断是否有方法需要重写
    if (hasMethodOverrides()) {
       getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
    }
 }
 protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
    // 获取对应的类中的对应方法名的个数
    int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    // 等于0抛出异常。上面已经验证有方法需要覆盖,这里为0肯定错误
    if (count == 0) {
       throw new BeanDefinitionValidationException(
             "Invalid method override: no method with name '" + mo.getMethodName() +
             "' on class [" + getBeanClassName() + "]");
    }
    else if (count == 1) {
       // 标记 MethodOverride 暂未被覆盖,避免参数类型检查的开销
       // Mark override as not overloaded, to avoid the overhead of arg type checking.
       mo.setOverloaded(false);
    }
 }

在Spring配置中存在lookup-method和replace-method时,这两个配置在加载xml的时候就会统一存放在BeanDefinition中的methodOverrides属性里。当创建bean的时候,AbstractAutowireCapableBeanFactory类会调用prepareMethodOverride方法来准备方法的覆盖。

知道上面这些概念与MethodOverrides这个属性的来历就很简单了,如果没有需要覆盖的,就不做处理,如果有,则判断是否超过 1 个,等于 1 个就

mo.setOverloaded(false);这个方法主要就是验证并准备给定的方法覆盖。为了之后创建 bean 时,是否需要检测参数。因为在创建 bean 的时候,一个方法可能会有多种入参方式,而最终在实例化的时候就要确定使用哪个构造函数,这个检测就很耗性能,所以做一个标记位

resolveBeforeInstantiation

该方法主要是调用 InstantiationAwareBeanPostProcessor 来进行一些处理,这里实际上是给了用户一次代替Spring来创建bean的机会,代码实现上非常简单直接调用的后处理器方法,就是有几个概念这里要提一下的。

 protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
       // Make sure bean class is actually resolved at this point.
       // 当前类并非合成类 && 存在 BeanPostProcessor (后处理器)
       if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
          // 1. 获取目标类
          Class<?> targetType = determineTargetType(beanName, mbd);
          if (targetType != null) {
             // 2. 先用实例前的后处理器获取 bean
             bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
             if (bean != null) {
                // 3. 前置没有则再使用后处理器应用
                bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
             }
          }
       }
       mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
 }

什么是合成类?什么是非合成类?为什么合成类不能使用BeanPostProcessor进行预处理?

  • 合成的含义是:这些构造体是由Java编译器引入的,并且在源代码中没有相应的构造体。这些合成构造体通常是编译器为了实现某些特性(如内部类访问外部类的私有成员)而生成的。例如,当AOP需要创建一个代理来拦截某个类的方法调用时,它可能会生成一个新的类(代理类),这个类在源代码中并不存在,因此它是合成的。这个代理类会包含一些额外的逻辑,比如在调用目标方法前后插入切面的代码。
  • 而非合成的则直接来自源代码
  • InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()方法是在Bean实例化之前被调用的,它的主要目的是允许我们在Bean实例化之前进行一些自定义的处理。但是,对于合成的类,由于它们是由编译器生成的,因此我们可能无法在Bean实例化之前对它们进行有效的处理(这个属于处理器的知识,后面会讲)。

doCreateBean

见名知意,这是一个创建 bean 的方法,直接下源码

 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
       throws BeanCreationException {
 ​
    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    // 如果是单例,先从缓存中移除
    if (mbd.isSingleton()) {
       instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    // 创建 bean 实例,并使用BeanWrapper包装器类来封装这个实例
    if (instanceWrapper == null) {
       instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 获取 bean 实例
    Object bean = instanceWrapper.getWrappedInstance();
    // 获取 bean 的类型
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
       // 设置目标解析类型
       mbd.resolvedTargetType = beanType;
    }
 ​
    // Allow post-processors to modify the merged bean definition.
    // 对合并后的bean定义进行同步锁定,确保其仅被后处理器修改一次
    synchronized (mbd.postProcessingLock) {
       // 未经过后置处理器处理
       if (!mbd.postProcessed) {
          try {
             // 应用合并bean定义的后处理器,允许对bean的定义进行扩展或修改
             applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
          }
          catch (Throwable ex) {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                   "Post-processing of merged bean definition failed", ex);
          }
          mbd.markAsPostProcessed();
       }
    }
 ​
    // 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(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
 ​
    // Initialize the bean instance.
    // 暴露在缓存中的 bean 实例
    Object exposedObject = bean;
    try {
       // 注入属性
       populateBean(beanName, mbd, instanceWrapper);
       // 初始化bean实例
       exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
       if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
          throw bce;
       }
       else {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
       }
    }
 ​
    // 处理早期单例曝光后的特殊情况
    if (earlySingletonExposure) {
       // 从缓存获取 bean 实例,此时缓存中的 bean 实例已经完成了初始化
       Object earlySingletonReference = getSingleton(beanName, false);
       if (earlySingletonReference != null) {
          // 如果暴露的 bean 实例与一开始的原始 bean 实例相同,那么将 exposeObject 替换为 从缓存中获取已经实例化完成的 bean
          if (exposedObject == bean) {
             exposedObject = earlySingletonReference;
          }
          // allowRawInjectionDespiteWrapping:允许在包装后仍然注入原始类型
          // hasDependentBean:有依赖当前 bean 的其他 bean
          else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
             // 获取依赖当前 bean 的其他 bean
             String[] dependentBeans = getDependentBeans(beanName);
             Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
             for (String dependentBean : dependentBeans) {
                // 移除给定bean名称的singleton实例(如果有的话),但前提是它没有用于类型检查以外的其他目的。
                if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                   // 能进来 则证明当前bean 的依赖 bean 还没有创建完成,还是使用的原始的 bean
                   actualDependentBeans.add(dependentBean);
                }
             }
             // 如果actualDependentBeans不为空,则证明当前 bean 还有依赖 bean 还没有创建完成,那么抛出异常
             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.");
             }
          }
       }
    }
 ​
    // Register bean as disposable.
    try {
       // 根据Scopse 注册bean
       registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
       throw new BeanCreationException(
             mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }
 ​
    return exposedObject;
 }
 ​
 ============================
   
 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);
     }
   }
 }

至此,下一篇将详细解析 doCreateBean,到底是怎么一步步创建bean 的