在对于Spring的所有解读中,Bean的生命周期都堪称是重中之重,甚至还有人称Spring就是个治理Bean的容器。Bean的生命周期之所以这么重要,被重复提及,是因为Spring的外围能力,比方对象创立(IOC)、属性注入(DI)、初始化办法的调用、代理对象的生成(AOP)等性能的实现,都是在bean的生命周期中实现的。分明了bean的生命周期,咱们能力晓得Spring的神奇魔法到底是什么,是怎么一步步赋能,让本来一般的java对象,最终变成领有超能力的bean的。
- 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的办法。
invokeInitMethods()调用初始化办法:
如果bean是InitializingBean的子类, 先调用afterPropertiesSet()。
回调自定义的initMethod,比方通过@Bean(initMethod = "xxx")指定的初始化办法。
回调后置处理器的后置办法,可能返回代理对象。其中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(仅单例的哦)。
- 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的销毁。