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

  • Post author:
  • Post category:其他




前言

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源码三千问】为什么要用三级缓存来解决循环依赖问题?二级缓存行不行?一级缓存行不行?



版权声明:本文为wang489687009原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。