Spring Bean生命周期

1. 简介

在【Spring核心流程梳理】我们介绍了Spring容器的refresh过程,但是我们并没有进入到Spring Bean的创建等生命周期等内容。

这里,就来梳理一下Spring Bean的生命周期。

我们还是关注流程,重点关注核心的入口,忽略具体实现的细节。

目标也很简单:

  1. 知道Spring Bean相关的扩展点,方便我们做自定义和阅读源码
  2. 当遇到问题的时候,能大致了解相关的debug入口

2. Bean处理器

2.1 BeanPostProcessor

在开始之前,先简单聊两句BeanPostProcessor,因为Bean的很多处理过程涉及到它,有点俄罗斯套娃的感觉。

1Object postProcessBeforeInitialization(Object bean, String beanName) 2Object postProcessAfterInitialization(Object bean, String beanName)

首先要弄清楚什么是Initialization,初始化,才知道是那之前那之后,我们可以做点啥。

初始化,就是我们调用类的实例bean已经创建好了,属性也设置好了。

调用我们自定义的:InitializingBean的afterPropertiesSet,init-method方法的过程。

所以,postProcessBeforeInitialization是在bean的属性设置之后被调用。

然后,afterPropertiesSet,init-method被调用。

最后,postProcessAfterInitialization被调用

2.2 InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor继承了BeanPostProcessor,多添加了下面3个方法:

1@Nullable 2default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { 3 return null; 4} 5default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { 6 return true; 7} 8@Nullable 9default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) 10 throws BeansException { 11 return null; 12}

实例化Instantiation是什么过程呢,简单的来说就是new过程,Spring当然是通过反射完成。

postProcessBeforeInstantiation就是在一个bean new之前被调用。 postProcessAfterInstantiation是在bean new之后被调用。

postProcessProperties这个方法是在这个bean的property和value解析完成之后被调用。

2.3 SmartInstantiationAwareBeanPostProcessor

SmartInstantiationAwareBeanPostProcessor继承了InstantiationAwareBeanPostProcessor,又添加了3个方法:

1// 探测bean的类型 2Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException; 3 4// 选择合适的构造器 5Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException; 6 7// 获得早期暴露的bean引用,Spring处理循环引用就用到这个方法 8Object getEarlyBeanReference(Object bean, String beanName) throws BeansException;

你也可以看看BeanPostProcessor与Spring无侵入扩展这篇文章。

3. AbstractAutowireCapableBeanFactory

如果Spring容器的核心是AbstractApplicationContext,那么Spring Bean相关的流程的核心就是AbstractAutowireCapableBeanFactory。

Bean生命周期最重要的流程就3个:

  1. 实例化(Instantiate):创建实例,相当于new过程
  2. 初始化(Initialize):设置值的过程,相当于setter过程
  3. 销毁:一般不需要,特殊的可以做释放资源等工作

注意:Instantiate和Initialize两个单词咋看很像,但是两个流程还是有很大差别,不要高混淆了

我们从AbstractApplicationContext的refresh方法中可以知道Bean创建的相关流程入口是:finishBeanFactoryInitialization方法。

调用链很长,分支很多,我们直接聚焦到核心的方法:AbstractAutowireCapableBeanFactory的doCreateBean方法。

3.1 doCreateBean方法

1protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 2 throws BeanCreationException { 3 4 // 实例化流程,创建bean实例 5 BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); 6 7 // 初始化bean实例 8 Object exposedObject = bean; 9 //设置property value,相当于setter过程 10 populateBean(beanName, mbd, instanceWrapper); 11 exposedObject = initializeBean(beanName, exposedObject, mbd); 12 13 // 销毁相关流程 14 registerDisposableBeanIfNecessary(beanName, bean, mbd); 15 return exposedObject; 16 }

上面的方法是伪代码,从原来代码中抽取出核心流程的部分,避免被无关的信息所干扰。

创建bean(new)的流程入口createBeanInstance这里我们暂时不关注,我本只需要知道,现在通过反射我们获取到一个Bean的实例了。

接下来我们来看初始化的流程,首先populateBean,populate是添加输入数据的意思,根据名字我们也能猜出大概是要执行setter方法了。

3.2 populateBean方法

1protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { 2 // InstantiationAwareBeanPostProcessor是BeanPostProcessor的子类,这里是调用其bean实例化之后的注入接口 3 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { 4 for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { 5 if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { 6 return; 7 } 8 } 9 } 10 11 // 后面是,获取的bean的PropertyValues,解析是否需要自动注入,检查PropertyValues有没有需要预处理等流程 12 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); 13 14 // 15 if (pvs != null) { 16 applyPropertyValues(beanName, mbd, bw, pvs); 17 } 18}

3.3 initializeBean方法

1protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { 2 // 检查bean是否是BeanNameAware、BeanClassLoaderAware、BeanFactoryAware调用对应方法 3 invokeAwareMethods(beanName, bean); 4 5 // 调用BeanPostProcessor的postProcessBeforeInitialization来处理bean 6 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 7 8 // 如果bean实现了InitializingBean,调用其afterPropertiesSet,如果有init-method,也会在afterPropertiesSet之后调用 9 invokeInitMethods(beanName, wrappedBean, mbd); 10 11 // 调用BeanPostProcessor的postProcessAfterInitialization来处理bean 12 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 13 return wrappedBean; 14}

@PostConstuct并没有在initializeBean处理,而是通过CommonAnnotationBeanPostProcessor、InitDestroyAnnotationBeanPostProcessor实现。

这2个类一看就能猜到是BeanPostProcessor,事实上的确是在InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization方法中处理。

因为initializeBean是初始化方法,@PostConstuct是在初始化之前执行,所以,调用顺序就能确定了:

  1. @PostConstuct方法
  2. afterPropertiesSet
  3. init-method

initializeBean方法中处理的Aware是:

  1. BeanNameAware给bean设置beanName
  2. BeanClassLoaderAware给bean设置ClassLoader
  3. BeanFactoryAware给bean设置BeanFactory

其他的Aware,通过ApplicationContextAwareProcessor,它是一个BeanPostProcessor,会在bean初始化之前,但是肯定在前面3个之后调用:

  1. EnvironmentAware:设置获取环境属性相关的Enviroment
  2. EmbeddedValueResolverAware:设置SpEL解析器
  3. ResourceLoaderAware:设置资源加载器
  4. ApplicationEventPublisherAware:设置事件发布器
  5. MessageSourceAware:设置国际化相关的MessageSource
  6. ApplicationStartupAware:设置启动指标监控相关的ApplicationStartup
  7. ApplicationContextAware:设置容器本身ApplicationContext

3.4 registerDisposableBeanIfNecessary方法

这个方法咱就不细入了,简单说一下逻辑:

  1. 处理bean中有@PreDestroy注解的方法
  2. 如果实现了DisposableBean接口处理其destroy方法
  3. 检查destroy-method,如:<bean id="x" class="XX" destroy-method="destroyMethod"/>

4. Spring Bean生命周期小结

先看一个简化流程: Spring Bean创建简单流程

在看一下常规流程逻辑调用链:

Spring Bean创建逻辑调用链

5. 循环依赖

Spring Bean的创建过程中还有一个重要的问题,依赖循环,这里大致说2句。

1public class A { 2 @Resource 3 private B b; 4} 5 6public class B { 7 @Resource 8 private A a; 9}

这可咋整哦?

逻辑可以通过的DefaultSingletonBeanRegistry的三级缓存来处理:

1// 缓存已经创建完成的bean 2private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); 3 4// 缓存ObjectFactory 5private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); 6 7// 缓存还未进行依赖注入和初始化方法调用的bean实例 8private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); 9 10 11protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException { 12 // 如果是单例,并且允许循环引用,并且这个实例正在创建中 13 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); 14 if (earlySingletonExposure) { 15 //把这个实例包装成ObjectFactory添加到三级缓存中,这样有其他引用就可以暂时获取这个未创建完成的bean 16 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 17 } 18 19 // 设置属性等初始化过程 20 21 return exposedObject; 22 }

用个简单的流程图来大致说明一下: Spring循环依赖

1public class A { 2 public A(B b) { 3 } 4} 5 6public class B { 7 public B(A a) { 8 } 9}

Spring的Bean创建流程我们也知道,构造函数上的循环依赖是没有办法处理的,实例化都执行不了。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Spring 源码分析之 bean 实例化原理

本次主要想写springbean的实例化相关的内容。创建springbean实例是springbean生命周期的第一阶段。bean的生命周期主要有如下几个步骤:<fontcolor'red'创建bean的实例</font给实例化出来的bean填充属性初始化bea通过IOC容器使用bean