SpringBoot Bean实例化流程解析

136 阅读7分钟

前言

在SpringBoot启动过程中会执行refreshContext()方法,而在其执行过程中,又会调用finishBeanFactoryInitialization()方法,该方法负责了Bean的实例化,那么本文将从源码跟读的角度来解析一下具体流程。

refresh()之前有讲过,传送门《SpringBoot 图文并茂万字拆解核心refresh方法

前置工作

新建一个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

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

image.png

判断是否存在conversionService

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

image.png

判断是否已有BeanFactoryPostProcessor

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

image.png

初始化LoadTimeWeaverAware

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

image.png

停止使用TempClassLoader

接下来将BeanFactorytempClassLoader属性设置为null

image.png

调用freezeConfiguration()

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

image.png

image.png

调用preInstantiateSingletons()

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

image.png

实例化Bean

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

首先会获取当前所有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

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

image.png

transformedBeanName

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

image.png

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

image.png

getSingleton

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

image.png

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

image.png

isPrototypeCurrentlyInCreation

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

获取BeanFactory

image.png

接着尝试获取父类BeanFactory,并调用父类BeanFactorygetBean方法获取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

这里进入DefaultSingletonBeanRegistrygetSingleton方法

image.png

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

image.png

createBean

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

image.png

resolveBeanClass

接着来到AbstractAutowireCapableBeanFactorycreateBean方法,首先会调用AbstractBeanFactoryresolveBeanClass方法对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

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

image.png

但其实最后返回的是null

image.png

instantiateBean

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

image.png

image.png

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

image.png

instantiate

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

image.png

BeanUtils.instantiateClass

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

image.png

BeanWrapper

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

image.png

可以看到最后返回的不是BeanInstance,而是把BeanInstance给包裹了一层,返回的BeanWrapper。这里使用到了23种设计模式之一的《装饰者模式

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中非常基础且重要的——反射

结尾

本文章源自《Learn SpringBoot》专栏,感兴趣的话还请关注点赞收藏.

上一篇文章:《SpringBoot 图文并茂万字拆解核心refresh方法

下一篇文章:《SpringBoot Aware使用及原理解析