原创 千锋侯哥
一. 前言
在面试过程中,经常有小伙伴会被问到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<BeanDefinitionHolder> doScan(String... basePackages) {
- Assert.notEmpty(basePackages, "At least one base package must be specified");
- Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
- //循环需要扫描的包
- for (String basePackage : basePackages) {
- //依次解析指定包下的各种Bean组件,返回BeanDefintion集合
- Set<BeanDefinition> 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<String> 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> T doGetBean(
- String name, @Nullable Class<T> 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注解标记的方法)。