原创 千锋侯哥
一. 前言
在面试过程中,经常有小伙伴会被问到Spring中Bean的生命周期,如果对Spring不了解可能对此类问题难以下手,就算通过百度查询到答案,也可能因为不理解而难以记忆,过段时间又忘记了,那么今天千锋侯哥就带小伙伴深入的解析下Spring中Bean的整个初始化过程。
二. IOC容器的初始化过程
我们都知道,IOC容器初始化时会进行各种Bean的初始化(单例非懒加载),因此在了解Bean的生命周期之前,我们先来看一下IOC容器的整个初始化过程。
我们先整体看下流程图,做到心中有数,理解无误。
2.1 开始初始化IOC容器
初始化IOC容器 - 基于常规的注解式容器(AnnotationConfig ApplicationContext)
//1、初始化IOC容器
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(AppConfiguration.class);
AppConfiguration为自定义的一个主配置类,代码如下:
//主配置类
@Configuration
//扫描包路径
@ComponentScan("com.qf")
public class AppConfiguration {
}
当前实际开发过程中,IOC容器肯定是随着Web服务器启动而启动的。下图是AnnotationConfigApplicationContext容器的其中一个构造方法(基于主配置类的容器创建)
2.2 BeanFactory的创建
SpringIOC容器初始化时,会在ApplicationContext内部创建一个BeanFactory对象。
代码在AnnotationConfigApplicationContext的父类GenericApplicationContext中
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
......
/**
* 创建一个BeanFacotry对象,实现类为DefaultListableBeanFactory
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
......
}
再来看下DefaultListableBeanFactory中的核心集合部分,这些集合主要保存Bean的描述信息(BeanDefinition)。当然这个时候,这些集合都是空的。
2.3 主配置类的加载
加载的代码较为复杂,这里就不给出了,小伙伴理解为主配置被作为普通的Bean对象,放入刚创建好的BeanFactory里就可以了,此时只是注册了Bean的信息,还未初始化为对象。
@Override
public void register(Class>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
.tag("classes", () -> Arrays.toString(componentClasses));
this.reader.register(componentClasses);
registerComponentClass.end();
}
2.4 BeanFactory的后置处理
这一步至关重要,其中有个BeanFactory的后置处理器 - ConfigurationClass PostProcessor,从名称可以看出,该处理器是为了初始化配置类而生的。上一步中注册到BeanFactory的主配置类,将会被这个后置处理器初始化为Bean对象,并且处理配置类上的@ComponentScan("com.qf")注解,进行其他组件的扫描,扫描的部分核心代码如下:
//基于包路径,扫描路径下的所有Bean,并且返回这些Bean的基本信息(BeanDefinition)集合
protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet<>();
//循环需要扫描的包
for (String basePackage : basePackages) {
//依次解析指定包下的各种Bean组件,返回BeanDefintion集合
Set candidates = findCandidateComponents(basePackage);
//再次完善各个Bean组件的基本信息
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//设置Bean的作用域类型
candidate.setScope(scopeMetadata.getScopeName());
//获取Bean的名称
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//检查当前bean是否已经注册过,如果没有注册,则继续
if (checkCandidate(beanName, candidate)) {
//将BeanDefinition对象包装成BeanDefinitionHolder对象
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//放入集合
beanDefinitions.add(definitionHolder);
//并且将当前BeanDefinition对象注册到IOC容器中
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
2.5 BeanFactory中其他Bean的初始化
上一步中,已经通过主配置类的扫描将各种业务Bean注册到BeanFactory了,接下来就是执行各种Bean的初始化流程了,这个过程也就是Bean的生命周期执行过程,我们稍后再来解析。
2.6 BeanFactory初始化完成
Bean初始化完成后,整个BeanFactory也就初始化完成了,IOC容器也就完成,相关数据集合也填充完毕,等待后续的业务执行。
三、Bean的初始化过程(生命周期)
接下来我们重点来看下Bean是如何初始化的,执行实际也就是上一节的第5步。当然,这个过程主要是初始化那些单例并且非懒加载的Bean,懒加载的Bean和原型的Bean是后续需要用到该Bean时才进行初始化(比如手动调用getBean等),此时才并未进行完整的初始化,暂且不讨论。
3.1 Bean初始化的流程图
老规矩,先看整体流程(红框部分)
因为后续的内容会用到,所以这里要跟大家区分两个概念:
Bean的创建
Bean的初始化
所谓的Bean的创建,其实就是指Bean对象通过构造方法,在堆内存中被创建出来的过程,此时站在Java的角度,该对象已经完成了初始化,但是内部的属性只拥有默认值,没有任何业务意义。
所谓的Bean的初始化,是站在Spring的角度,还需要对已经创建好的Bean进行后续的一些操作,比如依赖注入之类的,这个过程会给Bean进行一些业务操作,成为一个真正的"成品",可以即拿即用。而这个过程正是Bean的生命周期过程。
3.2 单例Bean初始化入口
接下来我们看下初始化Bean的核心方法,从名字就可以看出,完成BeanFactory的初始化,注释意为,初始化所有的非懒加载单例Bean。
其中的核心调用方法,初始化所有单例Bean
@Override
public void preInstantiateSingletons() throws BeansException {
....
//获取前面注册过的所有Bean的名称,转储到一个新集合
List beanNames = new ArrayList<>(this.beanDefinitionNames);
//循环所有Bean的名称,依次处理
for (String beanName : beanNames) {
//根据Bean的名称获取Bean的基本信息(BeanDefinition)
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//判断是否为非抽象、单例、非懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//判断是否为FactoryBean对象,
if (isFactoryBean(beanName)) {
//处理FactoryBean的初始化
}
else {
//普通Bean的初始化过程.....
getBean(beanName);
}
}
}
// 触发部分Bean的初始化的回调方法
//.....
}
3.3 单例Bean的创建(基于反射)
getBean方法,是通过Bean的名称获取Bean对象,该方法中就会判断IOC容器中是否存在Bean对象,如果不存在就会执行初始化流程,核心方法如下:
//该方法在getBean方法中被调用
protected T doGetBean(
String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//获得bean的名称
String beanName = transformedBeanName(name);
Object beanInstance;
//从缓存中获取单例Bean的缓存(为了解决循环依赖的设计)
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//从缓存已经获取缓存的Bean对象的处理逻辑
......
} else {
//缓存中没有找到单例Bean对象的处理逻辑
if (mbd.isSingleton()) {
//单例Bean的初始化逻辑【核心】
sharedInstance = getSingleton(beanName, () -> {
try {
//创建Bean对象,底层通过反射实现,具体分析见下方
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
//原型模式的处理逻辑,IOC容器初始化时并不会触发原型模式的初始化
.....
} else {
//其他作用域类型的处理逻辑
.....
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
//createBean方法中的核心方法doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
//核心 - 反射创建Bean对象,并且封装到BeanWrapper对象(Bean的包装器)中
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//获得当前Bean对象
Object bean = instanceWrapper.getWrappedInstance();
Class> beanType = instanceWrapper.getWrappedClass();
.....
Object exposedObject = bean;
try {
//核心 - 给Bean的属性进行依赖注入,方法翻译过来叫填充Bean
populateBean(beanName, mbd, instanceWrapper);
//核心 - 然后执行Bean的后续初始化过程,具体细节见下方
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
.....
//返回Bean对象
return exposedObject;
}
3.4 单例Bean的初始化
上一步已经展示了,Spring合适创建了Bean对象,以及依赖注入和初始化过程。这里重点来看下Bean的后续初始化过程,核心代码如下:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//核心 - 调用Bean的各种XxxxAware接口的方法,进行相关属性填充
invokeAwareMethods(beanName, bean);
//核心 - 调用BeanPostProcessor的前置处理方法
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//核心 - 调用Bean的初始化方法(init-method或者@PostConstruct注解标记的方法)
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
//核心 - 调用BeanPostProcessor的后置处理方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
四、总结
因为Spring拥有很庞大的体系结构,没办法介绍的面面俱到,因此摘了部分核心代码,配合流程图讲解,基本把整个Bean的初始化乃至整个IOC容器的初始化过程,简述了出来。如果小伙伴想要更加深入的了解Spring源码,可以配合debug,走一遍IOC初始化的流程。
最后再总结下整个Bean的整个生命周期过程:
1、Spring通过反射创建Bean对象;
2、完成当前Bean的依赖注入(成员变量填充);
3、如果Bean有实现Aware接口,则调用各种Aware接口的方法设置属性;
4、执行BeanPostProcessor的前置方法(通常是一个集合,形成一个调用链,依次执行);
5、完成开发者自定义的初始化方法(init-method或者@PostConstruct注解标记的方法);
6、执行BeanPostProcessor的后置方法(通常是一个集合,形成一个调用链,依次执行);
7、完成初始化,将Bean放入BeanFactory集合中(核心是一个Map集合);
8、Bean对象随着BeanFactory关闭而销毁,执行开发者自定义的销毁方法(destory-method或者@PreDestory注解标记的方法)。