前言
在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使用及原理解析》