在关于Spring的一切解读中,Bean的生命周期都可谓是重中之重,甚至还有人称Spring便是个办理Bean的容器。Bean的生命周期之所以这么重要,被重复提及,是由于Spring的中心才干,比方目标创立(IOC)
、特点注入(DI)
、初始化办法的调用
、署理目标的生成(AOP)
等功能的完结,都是在bean的生命周期中完结的。清楚了bean的生命周期,咱们才干知道Spring的奇特魔法终究是什么,是怎样一步步赋能,让原本一般的java目标,最终变成拥有超才干的bean的。
1. bean的生命周期
Spring的生命周期大致分为:创立
-> 特点填充
-> 初始化bean
-> 运用
-> 毁掉
几个中心阶段。咱们先来简略了解一下这些阶段所做的工作:
- 创立阶段主要是创立目标,这儿咱们看到,目标的创立权交由Spring办理了,不再是咱们手动new了,这也是IOC的概念。
- 特点填充阶段主要是进行依靠的注入,将当时目标依靠的bean目标,从Spring容器中找出来,然后填充到对应的特点中去。
- 初始化bean阶段做的工作相对比较复杂,包含回调各种Aware接口、回调各种初始化办法、生成AOP署理目标也在该阶段进行,该阶段主要是完结初始化回调,后边咱们慢慢剖析。
- 运用bean阶段,主要是bean创立完结,在程序运转期间,供给服务的阶段。
- 毁掉bean阶段,主要是容器封闭或停止服务,对bean进行毁掉处理。
当然,bean的生命周期中还包含其他的流程,比方露出工厂目标等,仅仅相对而言都是为其他功能做伏笔和预备的,再讲到对应功能时,咱们在做详细剖析。
1.1 创立bean
目标的创立是bean生命周期的第一步,毕竟要先有1才干有0嘛。创立目标的办法有许多,比方 new
、反射
、clone
等等,Spring是怎样创立目标的呢?绝大多数状况下,Spring是经过反射来创立目标的
,不过假如咱们供给了Supplier
或许工厂办法
,Spring也会直接运用咱们供给的创立办法。
咱们从源码动身,看一下Spring是怎么挑选创立办法的:
// 源码坐落 AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 再次解析BeanDefinition的class,保证class现已被解析
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 1: 假如供给了Supplier,经过Supplier发生目标
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 2: 假如有工厂办法,运用工厂办法发生目标
// 在@Configration装备@Bean的办法,也会被解析为FactoryMethod
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
//...省掉部分代码
// 3: 揣度结构办法
// 3.1 执行后置处理器,获取候选结构办法
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 3.2 需求主动注入的状况
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 3.3 默许运用没有参数的结构办法
return instantiateBean(beanName, mbd);
}
经过咱们跟踪源码,发现Spring揣度创立办法仍是比较聪明的,详细逻辑是:
- 先判别是否供给了Supplier,假如供给,则经过Supplier发生目标。
- 再判别是否供给工厂办法,假如供给,则运用工厂办法发生目标。
- 假如都没供给,需求进行结构办法的揣度,逻辑为:
- 假如仅有一个结构办法,会直接运用该结构办法(
假如结构办法有参数,会主动注入依靠参数
) - 假如有多个结构参数,会判别有没有加了
@Autowired
注解的结构参数:- 假如没有,Spring默许挑选无参结构办法;
- 假如有,且有
@Autowired(required=true)
的结构办法,就会挑选该结构办法; - 假如有,可是没有
@Autowired(required=true)
的结构办法,Spring会从一切加了@Autowired
的结构办法中,依据结构器参数个数、类型匹配程度等综合打分,挑选一个匹配参数最多,类型最准确的结构办法。
- 假如仅有一个结构办法,会直接运用该结构办法(
关于创立bean时,详细怎么挑选结构办法的,本文咱们不详细展开。由于本文宗旨在于剖析bean的生命周期,咱们只需求简略知道Spring会挑选一个结构办法,然后经过反射创立出目标即可。其实在阅览Spring源码的时分,小伙伴们也必定要学会抓大放小,要点重视中心流程,细枝末节的当地能够先战术性疏忽,后续有需求时再回过头剖析也不迟,千万不要陷进去,迷失了方向。
这儿给感兴趣的小伙伴附上一张流程图,感兴趣的小伙伴也能够留言,后续咱们也能够独自剖析。
1.2 merged BeanDefinition
本阶段是Spring供给的一个拓宽点,经过MergedBeanDefinitionPostProcessor
类型的后置处理器,能够对bean对应的BeanDefinition
进行修正。Spring本身也充分利用该拓宽点,做了许多初始化操作(并没有修正BeanDefinition),比方查找标注了@Autowired
、 @Resource
、@PostConstruct
、@PreDestory
的特点和办法,便利后续进行特点注入和初始化回调。当然,咱们也能够自定义完结,用来修正BeanDefinition信息或许咱们需求的初始化操作,感兴趣的小伙伴能够自行试一下哦。
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
1.3 露出工厂目标
本阶段主要是将前期bean目标提早放入到三级缓存singletonFactories
中,为循环依靠做支持。在后续进行特点填充时,假如发生循环依靠,能够从三级缓存中经过getObject()
获取该bean,完结循环依靠场景下的主动注入。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 做循环依靠的支持 将前期实例化bean的ObjectFactory,增加到单例工厂(三级缓存)中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
该阶段彻底是为了支撑循环依靠的,是Spring为处理循环依靠埋的伏笔,在Bean的生命周期中彻底能够疏忽。这儿为了完整性,和小伙伴们简略提及一下。
假如对Spring怎么处理循环依靠不是很清楚的话,能够看笔者的另一篇文章 聊透Spring循环依靠,详细剖析了Spring循环依靠的处理之道,对本阶段的内容也有详细的叙说。
1.4 特点填充
本阶段完结了Spring的中心功能之一:依靠注入,包含主动注入
、@Autowired注入
、@Resource注入
等。Spring会依据bean的注入模型(默许不主动注入
),挑选依据名称主动注入仍是依据类型主动注入。然后调用InstantiationAwareBeanPostProcessor#postProcessProperties()
完结@Autowired和@Resource的特点注入。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 省掉部分代码
// 获取bean的注入类型
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 1: 主动注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
// 依据名称注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 依据类型注入
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 2: 调用BeanPostProcessor,完结@Autowired @Resource特点填充
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 要点: 完结@Autowired @Resource特点填充
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
// 需求注入的特点,会过滤掉Aware接口包含的特点(经过ignoreDependencyInterface增加)
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 3: 依靠检查
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 4: 将特点应用到bean中
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
关于依靠注入,笔者在 聊透Spring依靠注入 中有详细剖析,不清楚的小伙伴能够先去感受一下Spring依靠注入的美妙之处。
1.5 初始化bean
该阶段主要做bean的初始化操作,包含:回调Aware接口
、回调初始化办法
、生成署理目标
等。
-
invokeAwareMethods()
:回调BeanNameAware
、BeanClassLoaderAware、BeanFactoryAware感知接口。 - 回调后置处理器的前置办法,其中:
- ApplicationContextAwareProcessor: 回调
EnvironmentAware
、ResourceLoaderAware、ApplicationContextAware
、ApplicationEventPublisherAware
、MessageSourceAware、EmbeddedValueResolverAware感知接口。 -
InitDestroyAnnotationBeanPostProcessor
:调用了标注了@PostConstruct的办法。
- ApplicationContextAwareProcessor: 回调
- invokeInitMethods()调用初始化办法:
- 假如bean是
InitializingBean
的子类, 先调用afterPropertiesSet()
。 - 回调自定义的initMethod,比方经过@Bean(initMethod = “xxx”)指定的初始化办法。
- 假如bean是
- 回调后置处理器的后置办法,可能回来署理目标。其中
AbstractAutoProxyCreator
和AbstractAdvisingBeanPostProcessor
都有可能发生署理目标,比方InfrastructureAdvisorAutoProxyCreator
完结了@Transactional
署理目标的生成,AsyncAnnotationBeanPostProcessor
完结了@Async署理目标的生成。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 1: 回调Aware接口中的办法
// 完结Aware办法的回调(BeanNameAware,BeanClassLoaderAware,BeanFactoryAware)
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 2: 调用before...办法
// ApplicationContextAwareProcessor: 其他Aware办法的回调
// InitDestroyAnnotationBeanPostProcessor: @PostConstruct办法的回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 3: 完结xml版别和@bean(initMethod)的init办法回调
invokeInitMethods(beanName, wrappedBean, mbd);
}
// 4: 调用after办法
// 要点: AOP生成署理目标
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
在初始化完结后,bean会被放到单例池中,正式开始自己的任务:为项目服务,比方接纳http请求,进行CRUD等等。后续有运用到该bean的当地,也是直接从单例池中获取,不会再次创立bean(仅单例的哦)。
2. bean的来龙去脉
2.1 bean的扫描阶段
现在咱们现已知道Spring bean是怎么创立的了,那什么时分创立这些bean呢,是遵从懒加载的思维,在实际运用的时分在创立吗?其实不是的,由于bean之间的复杂关系和生命周期的原因,Spring在容器启动的时分,就会实例化这些bean,然后放到单例池中,即用即取。并且在创立前、创立中、创立后都会做许多检查,保证创立的bean是符合要求的,这些咱们就不赘述了。
言归正传,细心的你必定发现,创立bean时主要是从RootBeanDefinition mbd
这个参数获取bean的相关信息的,其实这便是大名鼎鼎的BeanDefinition
,其中封装了关于bean的元数据信息,关于BeanDefinition,后续咱们会独自解说,这儿咱们先了解为bean的元数据信息即可。那么这些元数据信息是什么时分解析的呢?
这就要说到Spring的类扫描了,其大致流程是:经过ASM字节码技术扫描一切的类
-> 找出需求Sp加了@Compont注解的(简略了解)
-> 封装成BeanDefinition
-> 存放到调集中
。后续再实例化bean的时分,就能够遍历这个调集,获取到BeanDefinition
,然后进行bean的创立了。
关于处理类扫描的
ConfigurationClassPostProcessor
后置处理器以及ConfigurationClassParser
和ComponentScanAnnotationParser
扫描器的详细细节,后续咱们独自解说,和本章节关系不大,咱们先简略了解即可。
2.2 实例化后回调
在前面的章节咱们剖析过:在容器中的bean实例化,放到单例池中之后,bean在创立阶段的生命周期就正式完结,进入运用中
阶段,敞开对完服务之路。的确,这便是创立bean的全过程,假如有小伙伴看过笔者之前的聊Spring事件的那篇文章(聊透Spring事件机制),会发现关于@EventListener
处理器的辨认注册,是在afterSingletonsInstantiated
阶段完结的。其实这儿也是一个拓宽点,咱们彻底能够完结SmartInitializingSingleton#afterSingletonsInstantiated()
,在bean初始化完结后会回调该办法,进而触发咱们自己的事务逻辑,故这儿咱们独自说一下。不清楚的小伙伴请移步先去了解一下哦。
2.3 bean的毁掉阶段
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ...省掉代码
try {
// 为bean注册DisposableBean,在容器封闭时,调用destory()
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
在创立bean的时分,会判别假如bean是DisposableBean
、AutoCloseable
的子类,或许有 destroy-method
等,会注册为可毁掉的bean,在容器封闭时,调用对应的办法进行bean的毁掉。