【老王读Spring IoC-3】Spring 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 实例创建时的调用堆栈

观察调用堆栈,是阅读源码的一个小技巧。可以快速的观察到程序从开始到断点处经过了哪些处理过程。
createBeanInstance

从调用堆栈中,可以看到,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 isn't 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 完整的创建过程:
doCreateBean

小结

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)

SpringIoC源码视频讲解:

课程地址
SpringIoC源码解读由浅入深https://edu.51cto.com/sd/68e86

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

源码测试工程下载:
老王读Spring IoC源码分析&测试代码下载
老王读Spring AOP源码分析&测试代码下载

公众号后台回复:下载IoC 或者 下载AOP 可以免费下载源码测试工程…

阅读更多文章,请关注公众号: 老王学源码
gzh


系列博文:
【老王读Spring IoC-0】Spring IoC 引入
【老王读Spring IoC-1】IoC 之控制反转引入
【老王读Spring IoC-2】IoC 之 BeanDefinition 扫描注册
【老王读Spring IoC-3】Spring bean 的创建过程
【老王读Spring IoC-4】IoC 之依赖注入原理
【老王读Spring IoC-5】Spring IoC 小结——控制反转、依赖注入

相关阅读:
【Spring源码三千问】@Resource 与 @Autowired 的区别
【Spring源码三千问】bean name 的生成规则
【Spring源码三千问】BeanDefinition详细分析
【Spring源码三千问】Spring 是怎样解决循环依赖问题的?
【Spring源码三千问】哪些循环依赖问题Spring解决不了?
【Spring源码三千问】@Lazy为什么可以解决特殊的循环依赖问题?
【Spring源码三千问】BeanDefinition注册、Bean注册、Dependency注册有什么区别?
【Spring源码三千问】Bean的Scope有哪些?scope=request是什么原理?
【Spring源码三千问】为什么要用三级缓存来解决循环依赖问题?二级缓存行不行?一级缓存行不行?

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老王学源码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值