老王读Spring IoC-3Spring bean 的创建过程

Posted 老王学源码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了老王读Spring IoC-3Spring bean 的创建过程相关的知识,希望对你有一定的参考价值。

@[TOC](bean 的创建过程)

前言

Spring 提供了"控制反转"的能力,也就是将 bean 的创建交由 Spring 去统一处理。
前文分析了要实现"控制反转"的功能,Spring 需要解决的问题是:

  1. BeanDefinition 的扫描和注册
  2. 根据 BeanDefinition 来创建 bean 的实例

可以说"BeanDefinition 的扫描和注册"只是前戏,bean 实例的创建才是主菜。
上一篇已经分析了 BeanDefinition 的扫描和注册,这里我们主要再分析一下 bean 实例的创建过程。

版本约定

Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

正文

一个普通的单例 bean,如果没有特殊的指定 FactoryMethod 或者 constructor 的话,就会使用默认的构造函数来创建 bean 的实例。
那么,我们可以为一个普通的单例 bean 添加一个默认的构造函数,然后在上面打上断点,来观察 bean 实例创建时的调用堆栈

从调用堆栈中,可以看到,bean 实例的创建是在执行 AbstractApplicationContext#finishBeanFactoryInitialization() 的时候,调用 AbstractBeanFactory#getBean() 触发的。
最终会调用 AbstractAutowireCapableBeanFactory#createBeanInstance():

/**
 * 通过一定的实例化策略,为指定的 bean 创建一个新的实例。  
 * 实例化策略为:  FactoryMethod --> constructor autowiring(构造注入) --> simple instantiation(调用默认构造函数)
 * Create a new instance for the specified bean, using an appropriate instantiation strategy: factory method, constructor autowiring, or simple instantiation.
 */
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // Make sure bean class is actually resolved at this point.
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isnt public, and non-public access not allowed: " + beanClass.getName());
    }

    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }

    // 1. 通过指定的 FactoryMethod 来创建 bean 的实例
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same bean...
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
        } else {
            return instantiateBean(beanName, mbd);
        }
    }

    // 2. 构造注入
    // Candidate constructors for autowiring?
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // Preferred constructors for default construction?
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // 3. 使用无参构造函数来创建 bean 的实例。(即默认的构造函数)
    // No special handling: simply use no-arg constructor.
    return instantiateBean(beanName, mbd);
}

补充:bean 创建的完整过程

createBeanInstance() 方法只是将 bean 的实例创建出来了,它还不是一个完整的 bean,因为 bean 里面依赖的属性还没有填充值。
AbstractAutowireCapableBeanFactory.doCreateBean() 的源码可以看到 bean 完整的创建过程:

小结

bean 实例的创建是在执行 AbstractApplicationContext#finishBeanFactoryInitialization() 的时候,调用 AbstractBeanFactory#getBean() 触发的。
最终是由 AbstractAutowireCapableBeanFactory#createBeanInstance() 方法来完成 bean 实例的创建的。
bean 实例的创建策略为(优先级级从前往后):

  1. 通过指定的 FactoryMethod 来创建
  2. 构造注入的方式(通过指定的构造函数)
  3. 通过默认的构造函数来创建

创建一个完整的 bean 分三个阶段:

  1. AbstractAutowireCapableBeanFactory#createBeanInstance()
    创建 bean 的实例
  2. AbstractAutowireCapableBeanFactory#populateBean()
    填充 bean 的依赖
  3. AbstractAutowireCapableBeanFactory#initializeBean()
    初始化 bean。
    对 bean 的实例执行一些初始化方法:
    awareMethods --> BeanPostProcessor --> initMethod(InitializingBean#afterPropertiesSet、指定的 initMethod)

如果本文对你有所帮助,欢迎点赞收藏

有关 Spring 源码方面的问题欢迎一起交流,备注:51cto (vx: Kevin-Wang001)

以上是关于老王读Spring IoC-3Spring bean 的创建过程的主要内容,如果未能解决你的问题,请参考以下文章

老王读Spring IoC-5Spring IoC 小结——控制反转依赖注入

老王读Spring IoC-2Spring IoC之BeanDefinition扫描注册的原理

老王读Spring Transaction-4Spring事务管理的核心原理——PlatformTransactionManager&TransactionStatus

老王读Spring Transaction从EnableTransactionManagement顺藤摸瓜,研究@Transactional的实现原理

老王读Spring Transaction-6spring-tx与DataSource连接池整合的原理

#yyds干货盘点# 老王读Spring AOP-4Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析