前言
在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
来到AbstractApplicationContext的refresh()方法,在该方法中调用了finishBeanFactoryInitialization()方法
判断是否存在conversionService
首先判断当前IOC容器中是否存在conversionService,有的话将其设置到BeanFactory中
判断是否已有BeanFactoryPostProcessor
接下来判断当前BeanFactory中是否存在BeanFactoryPostProcessor,没有的话注册一个默认的实现
初始化LoadTimeWeaverAware
接着查询当前IOC容器中是否存在LoadTimeWeaverAware的实现,有的话则进行初始化。该类是使用AOP时做织入的一个工具类,一般情况下开发不会使用到它,所以这里其实并不会执行到循环体中的getBean()
停止使用TempClassLoader
接下来将BeanFactory的tempClassLoader属性设置为null
调用freezeConfiguration()
接下来调用freezeConfiguration()方法,该方法主要是做一个冻结声明,即声明在此期间无法再向BeanFactory注册新的Bean定义
调用preInstantiateSingletons()
最后也是最关键的,调用preInstantiateSingletons()方法进行Bean的实例化
实例化Bean
最终其实会调用到DefaultListableBeanFactor的preInstantiateSingletons()方法。
首先会获取当前所有Bean定义的名称,并进行遍历
Tips:除了之前定义的service,controller,config...也包含了Spring内置的一些Bean
接着根据名称获取相关的BeanDefinition,也就是Bean的定义,它包括了Bean的一些元信息,比如是否单例,是否延迟初始化,该Bean依赖项等。
Tips:这里为了避免混淆视听,我事先已经在debug断点处加上了触发条件,只有beanName是restService时,断点才生效。
可以看到Spring会先根据BeanDefinition判断出当前类是否抽象类,是否单例,是否延迟加载。只有当当前BeanDefinition满足既不是抽象类,也不延迟加载的单例时,才会进行操作。
接着还会判断当前Bean是否实现了FactoryBean的接口,是的话则还要对Bean做一些处理。
因为之前创建的RestService没有实现FactoryBean接口,所以直接调用getBean方法
doGetBean
接着走到AbstractBeanFactory的doGetBean()方法,该方法主要作用就是返回一个指定的Bean实例
transformedBeanName
首先是对Bean的名称做一个处理,其中包含了若BeanName中包含了FACTORY_BEAN_PREFIX的话,则将其从BeanName中删除的逻辑
同时如果有设置别名的话,也会获取真正的BeanName再返回
getSingleton
接着进入DefaultSingletonBeanRegistry的getSingleton方法,该方法主要作用是返回给定名称注册的单例对象
虽然这里逻辑很长,还用到了双检锁机制,但是其实从singletonObjects中检查是否有对应beanName的Bean存在时,因为是第一次创建,所以singletonObjects中并不存在相关的Bean,直接没进if方法体,就返回null了
isPrototypeCurrentlyInCreation
接着执行
AbstractBeanFactory的isPrototypeCurrentlyInCreation方法,该方法主要是检查该beanName相关的Bean是否在当前线程创建中,因为我们这里还没有进行创建,所以这里方法返回false。
获取BeanFactory
接着尝试获取父类BeanFactory,并调用父类BeanFactory的getBean方法获取Bean,但是因为当前的beanFactory已经是最顶级的了,所以直接跳过大段代码。
Tips:Spring中BeanFactory跟JVM实现双亲委派机制的ClassLoader一样,也存在子级父级关系
markBeanAsCreated
接着执行markBeanAsCreated方法,这里也用到了双检锁机制,方法很简单,就是将beanName添加到alreadyCreated当中,算是做一个标识,标识当前beanName对应的Bean正在创建当中。
getMergedLocalBeanDefinition
接着调用getMergedLocalBeanDefinition方法获取BeanDefinition,并检查是否是抽象类,是的话直接抛出异常
检查是否存在依赖
接着检查当前要实例化的
Bean是否和别的Bean存在依赖关系,是的话得先把所依赖的Bean创建好,才能继续实例化当前的Bean。
因为RestService中没有依赖什么别的Bean,所以这里略过一段代码
根据作用域创建Bean
接着便是根据作用域的不同,使用不同方式创建Bean
getSingleton
这里进入DefaultSingletonBeanRegistry的getSingleton方法
这里首先还是会检查当前Bean是否已初始化,是的话直接返回
createBean
接着调用ObjectFactory的getObject方法,因为传参时是传递了一个匿名内部类,所以重新回到AbstractBeanFactory,可以看到调用了createBean方法
resolveBeanClass
接着来到AbstractAutowireCapableBeanFactory的createBean方法,首先会调用AbstractBeanFactory的resolveBeanClass方法对BeanDefinition对应的Class做一个解析,这里因为之前已经过了,所以直接返回。
resolveBeforeInstantiation
接着来到resolveBeforeInstantiation方法,可以看到如果它返回的Bean 不为空,那么将直接返回,意味着Bean实例化完成。
接着深入查看具体实现细节,可以看到会判断当前IOC容器是否存在InstantiationAwareBeanPostProcessor接口的实现
如果存在InstantiationAwareBeanPostProcessor接口实现,则会调用其postProcessBeforeInstantiation方法,如果该方法返回值不为空,那么直接返回,并且调用postProcessAfterInitialization方法再对返回值做一些处理
因为当前项目中并没有存在InstantiationAwareBeanPostProcessor接口实现,所以直接返回的是null
doCreateBean
所以初始化Bean的重任还是交给了doCreateBean方法
首先判断当前Bean是否单例,是的话将其从factoryBeanInstanceCache中移除
createBeanInstance
接着进入createBeanInstance方法,首先调用getInstanceSupplier方法判断当前BeanDefinition是否从其它配置加载的,然后调用getFactoryMethodName方法判断当前BeanDefinition是否存在工厂方法,RestService两个条件都不满足,所以会一路执行到后续代码。
determineConstructorsFromBeanPostProcessors
接着执行到determineConstructorsFromBeanPostProcessors方法,该方法主要是确定使用哪个构造器来初始化Bean
可以看到内部实现其实是依靠调用SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors方法来进行确定的
但其实最后返回的是null
instantiateBean
最后来到instantiateBean方法,由注释也可以看出,该方法就是在Bean无需做特殊处理,调用默认无参构造函数即可初始化时调用的。
首先调用getInstantiationStrategy方法获取实例化策略,可以看到默认实例化策略是CglibSubclassingInstantiationStrategy
instantiate
接着调用instantiate方法,在该方法中利用反射机制获取类默认构造函数
BeanUtils.instantiateClass
最后调用BeanUtils的instantiateClass方法进行构建,可以看出其实该方法内部就是用了Java的反射机制进行类的实例构建
BeanWrapper
Bean实例成功创建后,会创建BeanWrapper实例来对Bean实例做一个包装,并调用initBeanWrapper方法对BeanWrapper进行初始化操作
可以看到最后返回的不是BeanInstance,而是把BeanInstance给包裹了一层,返回的BeanWrapper。这里使用到了23种设计模式之一的《装饰者模式》
applyMergedBeanDefinitionPostProcessors
接着调用applyMergedBeanDefinitionPostProcessors方法,该方法本质即获取所有MergedBeanDefinitionPostProcessor实现,并逐个调用其postProcessMergedBeanDefinition方法
populateBean
接着执行populateBean方法,该方法主要用来填充当前的BeanInstance
会获取当前BeanDefinition的所有Property,并判断以何种方式进行自动注入,根据类型?根据名称?
还可以看到会尝试获取所有InstantiationAwareBeanPostProcessor实现,并调用其postProcessProperties方法
总结
在Spring实例化Bean的过程中,BeanDefinition几乎贯穿了整个流程,而BeanDefinition是一个对象在Spring中的描述,Spring通过操作BeanDefinition来完成Bean的实例化和属性注入,而实例化的过程中又使用到了Java中非常基础且重要的——反射
结尾
本文章源自《Learn SpringBoot》专栏,感兴趣的话还请关注点赞收藏.
上一篇文章:《SpringBoot 图文并茂万字拆解核心refresh方法》
下一篇文章:《SpringBoot Aware使用及原理解析》