Spring Bean 生命周期解读

1: Bean在Spring容器中是如何存储和定义的

Bean在Spring中的定义是org.springframework.beans.factory.config.BeanDefinition接口,BeanDefinition里面存储的就是我们编写的Java类在Spring中的元数据,包括了以下主要的元数据信息:

1:Scope(Bean类型):包括了单例Bean(Singleton)和多实例Bean(Prototype)

2:BeanClass: Bean的Class类型

3:LazyInit:Bean是否需要延迟加载

4:AutowireMode:自动注入类型

5:DependsOn:Bean所依赖的其他Bean的名称,Spring会先初始化依赖的Bean

6:PropertyValues:Bean的成员变量属性值

7:InitMethodName:Bean的初始化方法名称

8:DestroyMethodName:Bean的销毁方法名称

同时BeanDefinition是存储到org.springframework.beans.factory.support.DefaultListableBeanFactory类中维护的BeanDefinitionMap中的,源码如下

Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

了解了BeanDefinition的基础信息和存储位置后,接下来看看创建好的Bean实例是存储在什么地方的,创建好的Bean是存储在:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry类中的

singletonObjects中的,Key是Bean的名称,Value就是创建好的Bean实例:

Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

了解了基本信息之后,就可以带着下面两个关键问题去分析Spring Bean的生命周期了:

1:Java类是如何被 Spring 扫描从而变成 BeanDefinition 的?

2:BeanDefinition是如何被 Spring 加工创建成我们可以直接使用的 Bean实例的?

2:Java类是如何被Spring扫描成为BeanDefinition的?

在Spring中定义Bean的方式有非常多,例如使用XML文件、注解,包括:@Component@Service@Configuration等,下面就以@Component注解为例来探究Spring是如何扫描我们的Bean的。我们知道使用@Component注解来标记Bean是需要配合@ComponentScan注解来使用的,而我们的主启动类上标注的@SpringBootApplication注解中就默认继承了@ComponentScan注解

@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication

所以最初的问题就转化成了@ComponentScan注解是如何在Spring中运作的

2.1 @ComponentScan注解是如何运作的

在Spring框架中,这个注解对应的处理类是ComponentScanAnnotationParser,这个类的parse方法是主要的处理逻辑,这个方法简要处理逻辑如下:

1:获取@ComponentScan注解中的basePackage属性,若没有则默认为该注解所标注类所在的包路径

2:使用ClassPathBeanDefinitionScannerscanCandidateComponents方法扫描classpath:+basePackage+**/*.class下的所有类资源文件

3:最后循环判断扫描的所有类资源文件,判断是否包含@Component注解,若有则将这些类注册到beandefinitionMap中

自此,我们代码里写的Java类,就被Spring扫描成BeanDefinition存储到了BeanDefinitionMap中了,扫描的细节大家可以去看看这个类的源码

3:Spring如何创建我们的Bean实例的

Spring把我们编写的Java类扫描成BeanDefinition之后,就会开始创建我们的Bean实例了,Spring将创建Bean的方法交给了org.springframework.beans.factory.support.AbstractBeanFactory#getBean方法,接下来就来看看getBean方法是如何创建Bean的

getBean方法的调用逻辑如下:getBean--> doGetBean --> createBean --> doCreateBean,最终Spring会使用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法来创建Bean,创建Bean实例的主要逻辑分为了四个部分:创建Bean实例,填充Bean属性,初始化Bean,销毁Bean,接下来我们分别对这个四个部分进行探究

3.1 创建Bean实例

创建Bean实例的方法入口如下:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

if (instanceWrapper == null) {
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}

这个方法的主要逻辑是:推断出创建该Bean的构造器方法和参数,然后使用Java反射去创建Bean实例

3.2 填充Bean属性值populateBean方法

在这个方法中,主要是解析Bean需要注入的成员属性,然后将这些属性注入到该Bean中,如果该Bean有依赖的其他Bean则会优先去创建依赖的Bean,然后返回来继续创建该Bean,注意这里就会产生Bean创建的循环依赖问题。

3.4:初始化Bean(initializeBean方法)

初始化Bean主要包括了四个部分:

3.4.1:invokeAwareMethods

在这个方法中主要调用实现的Aware接口中的方法,包括了BeanNameAware.setBeanName,BeanClassLoaderAware.setBeanClassLoader,BeanFactoryAware.setBeanFactory,这三个方法

Aware接口的功能:通过调用Aware接口中的set方法,将Spring容器中对应的Bean注入到正在创建的Bean中

3.4.2:调用前置处理方法:applyBeanPostProcessorsBeforeInitialization

在这个方法中主要是获取Spring容器中所有实现了org.springframework.beans.factory.config.BeanPostProcessor接口的的实现类,然后循环调用postProcessBeforeInitialization方法来加工正在创建的Bean

所以在这个方法中我们可以自定义BeanPostProcessor来扩展Bean的功能,实现自己的加工逻辑

3.4.3:调用Bean相关的初始化方法:

3.4.3.1 如果是InitializingBean则调用afterPropertiesSet方法

在这个流程中,Spring框架会判断正在创建的Bean是否实现了InitializingBean接口,如果实现了就会调用afterPropertiesSet方法来执行代码逻辑。

3.4.3.2 调用自定义初始化方法:initMethod

在这个流程中主要调用我们自定义的初始化方法,例如在xml文件中配置的init-method和destory-method或者使用注解配置的@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod") 方法

3.4.3.3:调用后置处理方法:applyBeanPostProcessorsAfterInitialization

在这个方法中主要是获取Spring容器中所有实现了org.springframework.beans.factory.config.BeanPostProcessor接口的的实现类,然后循环调用postProcessAfterInitialization来加工正在创建的Bean

在这个方法中我们可以自定义BeanPostProcessor来扩展Bean的功能,实现自己的加工逻辑

4:注册Bean销毁方法

在这里主要是注册Bean销毁时Spring回掉的方法例如:

1:xml文件中配置的destroy-method方法或者@Bean注解中配置的destroyMethod方法

2:org.springframework.beans.factory.DisposableBean接口中的destory方法

5:总结

到这里,从我们编写的Java类到Spring容器中可使用的Bean实例的创建过程就完整的梳理完成了,了解Bean的创建过程能够使我们更加熟悉Bean的使用方法,同时我们也可以在创建Bean的过程中新增自己的处理逻辑,从而实现将自己的组件接入Spring框架

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值