SpringBoot Bean实例化流程解析

 更新时间:2023年08月28日 09:58:24   作者:LBruse  
在SpringBoot启动过程中会执行refreshContext()方法,而在其执行过程中,又会调用finishBeanFactoryInitialization()方法,该方法负责了Bean的实例化,那么本文将从源码跟读的角度来解析一下具体流程

前置工作

新建一个RestService,代码如下

package geek.springboot.application.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
/**
 * Rest Service
 *
 * @author Bruse
 */
@Slf4j
@Service
public class RestService {
    @PostConstruct
    public void init() {
        log.info("RestService init....");
    }
}

finishBeanFactoryInitialization

来到 AbstractApplicationContext refresh() 方法,在该方法中调用了 finishBeanFactoryInitialization() 方法

image.png

判断是否存在conversionService

首先判断当前IOC容器中是否存在 conversionService ,有的话将其设置到 BeanFactory

image.png

判断是否已有BeanFactoryPostProcessor

接下来判断当前 BeanFactory 中是否存在 BeanFactoryPostProcessor ,没有的话注册一个默认的实现

image.png

初始化LoadTimeWeaverAware

接着查询当前IOC容器中是否存在 LoadTimeWeaverAware 的实现,有的话则进行初始化。该类是使用AOP时做织入的一个工具类,一般情况下开发不会使用到它,所以这里其实并不会执行到循环体中的 getBean()

image.png

停止使用TempClassLoader

接下来将 BeanFactory tempClassLoader 属性设置为null

image.png

调用freezeConfiguration()

接下来调用 freezeConfiguration() 方法,该方法主要是做一个 冻结 声明,即声明在此期间无法再向 BeanFactory 注册新的Bean定义

image.png

image.png

调用preInstantiateSingletons()

最后也是最关键的,调用 preInstantiateSingletons() 方法进行Bean的实例化

image.png

实例化Bean

最终其实会调用到 DefaultListableBeanFactor preInstantiateSingletons() 方法。

首先会获取当前所有Bean定义的名称,并进行遍历

image.png

Tips:除了之前定义的service,controller,config...也包含了Spring内置的一些Bean

接着根据名称获取相关的 BeanDefinition ,也就是Bean的定义,它包括了Bean的一些元信息,比如是否单例,是否延迟初始化,该Bean依赖项等。

image.png

Tips:这里为了避免混淆视听,我事先已经在debug断点处加上了触发条件,只有beanName是restService时,断点才生效。

image.png

可以看到Spring会先根据 BeanDefinition 判断出当前类是否 抽象类 ,是否 单例 ,是否 延迟加载 。只有当当前 BeanDefinition 满足既不是 抽象类 ,也不 延迟加载 单例 时,才会进行操作。

接着还会判断当前 Bean 是否实现了 FactoryBean 的接口,是的话则还要对 Bean 做一些处理。

因为之前创建的 RestService 没有实现 FactoryBean 接口,所以直接调用 getBean 方法

image.png

doGetBean

接着走到 AbstractBeanFactory doGetBean() 方法,该方法主要作用就是返回一个指定的Bean实例

image.png

transformedBeanName

首先是对 Bean 的名称做一个处理,其中包含了若 BeanName 中包含了 FACTORY_BEAN_PREFIX 的话,则将其从 BeanName 中删除的逻辑

image.png

同时如果有设置 别名 的话,也会获取真正的 BeanName 再返回

image.png

getSingleton

接着进入 DefaultSingletonBeanRegistry getSingleton 方法,该方法主要作用是 返回给定名称注册的单例对象

image.png

虽然这里逻辑很长,还用到了 双检锁 机制,但是其实从 singletonObjects 中检查是否有对应 beanName Bean 存在时,因为是第一次创建,所以 singletonObjects 中并不存在相关的 Bean ,直接没进 if 方法体,就返回 null

image.png

isPrototypeCurrentlyInCreation

image.png

接着执行 AbstractBeanFactory isPrototypeCurrentlyInCreation 方法,该方法主要是检查该 beanName 相关的 Bean 是否在当前线程创建中,因为我们这里还没有进行创建,所以这里方法返回false。

获取BeanFactory

image.png

接着尝试获取父类 BeanFactory ,并调用父类 BeanFactory getBean 方法获取 Bean ,但是因为当前的 beanFactory 已经是最顶级的了,所以直接跳过大段代码。

Tips:Spring中BeanFactory跟JVM实现双亲委派机制的ClassLoader一样,也存在子级父级关系

markBeanAsCreated

接着执行 markBeanAsCreated 方法,这里也用到了 双检锁 机制,方法很简单,就是将 beanName 添加到 alreadyCreated 当中,算是做一个标识,标识当前 beanName 对应的 Bean 正在创建当中。

image.png

getMergedLocalBeanDefinition

接着调用 getMergedLocalBeanDefinition 方法获取 BeanDefinition ,并检查是否是抽象类,是的话直接抛出异常

image.png

image.png

检查是否存在依赖

image.png

接着检查当前要实例化的 Bean 是否和别的Bean存在依赖关系,是的话得先把所依赖的 Bean 创建好,才能继续实例化当前的 Bean

因为 RestService 中没有依赖什么别的 Bean ,所以这里略过一段代码

根据作用域创建Bean

接着便是根据作用域的不同,使用不同方式创建 Bean

image.png

getSingleton

这里进入 DefaultSingletonBeanRegistry getSingleton 方法

image.png

这里首先还是会检查当前 Bean 是否已初始化,是的话直接返回

image.png

createBean

接着调用 ObjectFactory getObject 方法,因为传参时是传递了一个 匿名内部类 ,所以重新回到 AbstractBeanFactory ,可以看到调用了 createBean 方法

image.png

resolveBeanClass

接着来到 AbstractAutowireCapableBeanFactory createBean 方法,首先会调用 AbstractBeanFactory resolveBeanClass 方法对 BeanDefinition 对应的 Class 做一个解析,这里因为之前已经过了,所以直接返回。

image.png

image.png

resolveBeforeInstantiation

image.png

接着来到 resolveBeforeInstantiation 方法,可以看到如果它返回的 Bean 不为空,那么将直接返回,意味着 Bean 实例化完成。

接着深入查看具体实现细节,可以看到会判断当前IOC容器是否存在 InstantiationAwareBeanPostProcessor 接口的实现

image.png

如果存在 InstantiationAwareBeanPostProcessor 接口实现,则会调用其 postProcessBeforeInstantiation 方法,如果该方法返回值不为空,那么直接返回,并且调用 postProcessAfterInitialization 方法再对返回值做一些处理

image.png

image.png

因为当前项目中并没有存在 InstantiationAwareBeanPostProcessor 接口实现,所以直接返回的是 null

doCreateBean

所以初始化 Bean 的重任还是交给了 doCreateBean 方法

image.png

首先判断当前 Bean 是否单例,是的话将其从 factoryBeanInstanceCache 中移除

image.png

createBeanInstance

接着进入 createBeanInstance 方法,首先调用 getInstanceSupplier 方法判断当前 BeanDefinition 是否从其它配置加载的,然后调用 getFactoryMethodName 方法判断当前 BeanDefinition 是否存在工厂方法, RestService 两个条件都不满足,所以会一路执行到后续代码。

image.png

determineConstructorsFromBeanPostProcessors

接着执行到 determineConstructorsFromBeanPostProcessors 方法,该方法主要是 确定使用哪个构造器来初始化Bean

image.png

可以看到内部实现其实是依靠调用 SmartInstantiationAwareBeanPostProcessor determineCandidateConstructors 方法来进行确定的

image.png

但其实最后返回的是 null

image.png

instantiateBean 

最后来到 instantiateBean 方法,由注释也可以看出,该方法就是在 Bean 无需做特殊处理,调用默认无参构造函数即可初始化时调用的。

image.png

image.png

首先调用 getInstantiationStrategy 方法获取 实例化策略 ,可以看到默认 实例化策略 CglibSubclassingInstantiationStrategy

image.png

instantiate

接着调用 instantiate 方法,在该方法中利用反射机制获取 类默认构造函数

image.png

BeanUtils.instantiateClass

最后调用 BeanUtils instantiateClass 方法进行构建,可以看出其实该方法内部就是用了Java的 反射机制 进行类的实例构建

image.png

BeanWrapper

Bean 实例成功创建后,会创建 BeanWrapper 实例来对 Bean 实例做一个包装,并调用 initBeanWrapper 方法对 BeanWrapper 进行初始化操作

image.png

可以看到最后返回的不是 BeanInstance ,而是把 BeanInstance 给包裹了一层,返回的 BeanWrapper

image.png

applyMergedBeanDefinitionPostProcessors

接着调用 applyMergedBeanDefinitionPostProcessors 方法,该方法本质即获取所有 MergedBeanDefinitionPostProcessor 实现,并逐个调用其 postProcessMergedBeanDefinition 方法

image.png

image.png

populateBean

接着执行 populateBean 方法,该方法主要用来填充当前的 BeanInstance

image.png

会获取当前 BeanDefinition 的所有 Property ,并判断以何种方式进行自动注入,根据类型?根据名称?

image.png

还可以看到会尝试获取所有 InstantiationAwareBeanPostProcessor 实现,并调用其 postProcessProperties 方法

image.png

总结

在Spring实例化Bean的过程中, BeanDefinition 几乎贯穿了整个流程,而 BeanDefinition 是一个对象在Spring中的描述,Spring通过操作 BeanDefinition 来完成 Bean 的实例化和属性注入,而实例化的过程中又使用到了Java中非常基础且重要的—— 反射

以上就是SpringBoot Bean实例化流程解析的详细内容,更多关于SpringBoot Bean实例化的资料请关注脚本之家其它相关文章!

相关文章

  • 解析Java编程中对于包结构的命名和访问

    解析Java编程中对于包结构的命名和访问

    这篇文章主要介绍了Java编程中对于包结构的命名和访问,是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-12-12
  • SpringMVC集成Web与MVC执行流程和数据响应及交互相关介绍全面总结

    SpringMVC集成Web与MVC执行流程和数据响应及交互相关介绍全面总结

    Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet,Spring MVC 角色划分清晰,分工明细,这篇文章主要介绍了SpringMVC集成Web与MVC执行流程和数据响应及交互
    2022-10-10
  • Java 实战项目锤炼之仿天猫网上商城的实现流程

    Java 实战项目锤炼之仿天猫网上商城的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+jsp+servlet+mysql+ajax实现一个仿天猫网上商城项目,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • 关于JSON.toJSONString()和Gson.toJson()方法的比较

    关于JSON.toJSONString()和Gson.toJson()方法的比较

    本文介绍了两种将Java对象转换为JSON字符串的方法:阿里的`JSON.toJSONString()`和谷歌的`Gson.toJson()`,通过一个示例,展示了当使用继承关系且子类覆盖父类字段时,`Gson`会报错,而`JSON`可以正常运行,作者建议在处理JSON相关操作时使用阿里的`JSON`类
    2024-11-11
  • Java实战员工绩效管理系统的实现流程

    Java实战员工绩效管理系统的实现流程

    只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+SSM+Mysql+Maven+HTML实现一个员工绩效管理系统,大家可以在过程中查缺补漏,提升水平
    2022-01-01
  • JAVA使用Gson解析json数据实例解析

    JAVA使用Gson解析json数据实例解析

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。接下来通过本文给大家介绍JAVA使用Gson解析json数据实例解析,需要的朋友参考下吧
    2016-03-03
  • Java实现解压zip和rar包的示例代码

    Java实现解压zip和rar包的示例代码

    这篇文章主要为大家详细介绍了如何使用Java实现解压zip和rar包,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-01-01
  • java正则表达式应用的实例代码

    java正则表达式应用的实例代码

    java正则的实例应用分析,大家从下面的代码中,就能知道java正则的应用与写法
    2008-10-10
  • Java对List进行排序的方法总结

    Java对List进行排序的方法总结

    在Java中,对List进行排序是一项常见的任务,Java提供了多种方法来对List中的元素进行排序,本文将详细介绍如何使用Java来实现List的排序操作,涵盖了常用的排序方法和技巧,需要的朋友可以参考下
    2024-07-07
  • Mybatis-Plus集成Sharding-JDBC与Flyway实现多租户分库分表实战

    Mybatis-Plus集成Sharding-JDBC与Flyway实现多租户分库分表实战

    这篇文章主要为大家介绍了Mybatis-Plus集成Sharding-JDBC与Flyway实现多租户分库分表实战,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11

最新评论