java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot Bean实例化

SpringBoot Bean实例化流程解析

作者: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实例化的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文