【Spring Bean 生命周期系列】传送门

1、Spring Bean生命周期: Bean元信息的配置与解析阶段

2、Spring Bean生命周期: Bean的注册

3、Spring Bean生命周期: BeanDefinition的合并过程

4、Spring Bean生命周期: Bean的实例化

5、Spring Bean生命周期:属性赋值阶段

6、Spring Bean生命周期:Bean的初始化阶段

写在前面

注:本文章使用的 SpringBoot 版本为 2.2.4.RELEASE,其 Spring 版本为 5.2.3.RELEASE

前言

接着上节继续分析,上节说了Bean属性赋值的过程,这节就聊一下初始化Bean的过程
initializeBean方法主要有四块内容

  • Bean Aware方法回调
  • BeanPostProcessor 初始化前回调
  • 执行初始化方法
  • BeanPostProcessor 初始化后回调

下面我们就按照这个顺序跟着源码逐块分析

Bean Aware方法回调

 private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {//如果当前Bean实现了BeanNameAware,则将beanName通过回调传给当前Beanif (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}//如果当前Bean实现了BeanClassLoaderAware,则将BeanClassLoader通过回调传给当前Beanif (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}//如果当前Bean实现了BeanFactoryAware,则将BeanFactory通过回调传给当前Beanif (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}}

这个方法主要实现了BeanNameAwareBeanClassLoaderAwareBeanFactoryAware三个Aware接口的回调。

下面就举例演示下

public class BeanAwareDemo implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(BeanAwareDemo.class);context.refresh();BeanAwareDemo bean = context.getBean(BeanAwareDemo.class);System.out.println("beanFactory==>" + bean.beanFactory);System.out.println("beanName==>" + bean.beanName);System.out.println("classLoader==>" + bean.classLoader);context.close();}private ClassLoader classLoader;@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {this.classLoader = classLoader;}private BeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}private String beanName;@Overridepublic void setBeanName(String name) {this.beanName = name;}
}

输出结果:

beanFactory==>org.springframework.beans.factory.support.DefaultListableBeanFactory@458c1321
beanName==>beanAwareDemo
classLoader==>sun.misc.Launcher$AppClassLoader@18b4aac2

看到这可能有同学会想:“那我平时经常用的ApplicationContextAware是什么时候,在哪里被回调的呢?”

我:别着急,剩下的一些常用Aware接口的回调时机、在哪里回调,我们先不再这里展开了,以后有时间了单独拿出来讨论。

Bean初始化前后阶段

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {//省略分析过的代码Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//初始化前回调wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//执行初始化方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {//省略异常信息}if (mbd == null || !mbd.isSynthetic()) {//初始化后回调wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}

这里呢,为了方便说明,将Bean初始化前后放到一起来分析了。

经过我们前面章节的分析,我们对BeanPostProcessor这个后置处理器也有了一些认识了。主要是通过postProcessBeforeInitializationpostProcessAfterInitialization两个方法在Bean初始化前与后对Bean进行些修饰。

一起来看下这两个方法吧!

 //初始化前回调
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {//将原始Bean对象存一份Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessBeforeInitialization(result, beanName);  // 如果有回调函数 返回null了,那么依然使用原始的Bean对象if (current == null) {return result;}//如果不返回null,则将返回值作为当前Bean对象,接着进行循环处理result = current;}return result;}//初始化后回调@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {//将原始Bean对象存一份Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);// 如果有回调函数 返回null了,那么依然使用原始的Bean对象if (current == null) {return result;}//如果不返回null,则将返回值作为当前Bean对象,接着进行循环处理result = current;}return result;}

这里不再给出栗子了,有兴趣的小伙伴可以去BeanPostProcessor浅析看一下

Bean 初始化方法

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {//判断当前Bean是否实现了InitializingBeanboolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {//省略日志输出//if条件成立 是Java安全代码逻辑可忽略,与else代码段实质操作一致if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {// 如果Bean实现了InitializingBean,那么这里回调afterPropertiesSet方法((InitializingBean) bean).afterPropertiesSet();}}//如果mbd不为空 且bean类型不是NullBeanif (mbd != null && bean.getClass() != NullBean.class) {//获取InitMethod方法名String initMethodName = mbd.getInitMethodName();//条件成立:1、存在initMethod方法 2、当前Bean不是InitializingBean或initMetodName不等于afterPropertiesSet 3、不是外部管理的initMethodsif (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {// 那么执行自定义InitMethod方法,根据方法名获取Method 反射调用invokeCustomInitMethod(beanName, bean, mbd);}}}

上面给出了afterPropertiesSetinitMethod两个初始化方法的调用过程及调用顺序,这里的initMethod与@Bean中initMethod属性是一致的。

有的小伙伴可能会说了:“那我平时还经常使用一种别的初始化方法呢?是用@PostConstruct”标注的,它不是在这里被调用吗?那它是在哪里被调用的?"

我: 还记得BeanPostProcessor浅析章节吗? 我们在那个章节介绍了一些常用的BeanPostProcessor,其中@PostConstruct就是在CommonAnnotationBeanPostProcessor被调用的。

其实CommonAnnotationBeanPostProcessor继承自InitDestroyAnnotationBeanPostProcessor,确切地说是两个类联合起来完成对@PostConstruct的解析和方法调用

还记得上面

Spring Bean生命周期:Bean的初始化阶段相关推荐

  1. Spring Bean生命周期: Bean的实例化

    [Spring Bean 生命周期系列]传送门 1.Spring Bean生命周期: Bean元信息的配置与解析阶段 2.Spring Bean生命周期: Bean的注册 3.Spring Bean生 ...

  2. springboot学习:bean生命周期

    1.bean 生命周期 bean创建-初始化-销毁 构造(对象创建): 单实例:在容器启动的时候创建对象; 多实例:在每次获取的时候创建对象: 初始化: 对象创建完成,并赋值好,调用初始化方法 销毁: ...

  3. Spring生命周期Bean初始化过程详解

    Spring生命周期Bean初始化过程详解 Spring 容器初始化 Spring Bean初始化 BeanFactory和FactoryBean 源码分析 Bean的实例化 preInstantia ...

  4. 《Spring揭秘》——IOC梳理2(容器启动,bean生命周期)

    IoC容器背后的秘密 主要分为两个阶段:容器启动阶段.Bean实例化阶段. 容器启动阶段: 容器需要依赖某些工具类(BeanDefinitionReader)对加载的Configuration Met ...

  5. 3、Spring Bean生命周期

    Spring Bean的生命周期只有四个阶段,每个阶段又有对应的扩展点,如下: 实例化 Instantiation 属性赋值 Populate 初始化 Initialization 销毁 Destru ...

  6. Spring Bean生命周期,就像人的一生

    这篇我们来看一看Spring中Bean的生命周期,我发现,和人的一生真的很像. 1 简单说说IoC和Bean IoC,控制反转,想必大家都知道,所谓的控制反转,就是把new对象的权利交给容器,所有的对 ...

  7. 【Spring】- Bean生命周期

    2019独角兽企业重金招聘Python工程师标准>>> Spring Bean的生命周期: bean对象实例化 属性注入 beanfactory ApplicationContext ...

  8. Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02

    文章目录 Pre 通俗流程 finishBeanFactoryInitialization Pre Spring5源码 - 06 Spring Bean 生命周期流程 概述 01 接上文 通俗流程 下 ...

  9. Spring Bean默认配置为单实例 Spring Bean生命周期

    2019独角兽企业重金招聘Python工程师标准>>> Spring 的Bean默认的是单例的. 如果不想单例需要如下配置: <bean id="user" ...

最新文章

  1. 机器学习(10)随机森林(预测泰坦尼克号旅客存活率)
  2. 怎么让修改的html持久化_redis持久化机制
  3. vue2.0搭建vue手脚架(vue-cli)
  4. 牛客 - 小朋友你是否有很多问号(容斥+组合数学)
  5. windows下连接db2数据库
  6. 指令 出厂_口碑营销_南澳出口木箱出厂价
  7. linux 批量替换文件内容及查找某目录下所有包含某字符串的文件(批量修改文件内容)...
  8. IIS经典模式与集成模式
  9. RDP大屏幕报表sql问题
  10. Activiti7工作流+Springboot快速入门
  11. 1.1信息安全基础概念
  12. Tumblr,instapaper分享
  13. 失眠就吃安眠药真的好吗?好心情送你沾枕到天亮的诀窍
  14. 基于matlab的脑瘤mr图像处理_基于电势能改进的区域生长脑肿瘤图像分割
  15. js的alert弹框中怎么写html,JavaScript实现alert弹框效果
  16. hdu 1429 胜利大逃亡(续)
  17. pythonapp自动化_基于python的App UI自动化环境搭建
  18. OpenStack核心组件原理与应用之Keystone
  19. 多元线性回归的spss应用
  20. 转载一篇关于泰迪很好的文章

热门文章

  1. 4端口书面切换器kvm切换器共享器
  2. 《一课经济学》七、房租管制和最低工资法
  3. 使用Piwigo管理您的照片
  4. 分享两个Latex在线公式编辑器的网站
  5. C语言也能写植物大战僵尸
  6. 分享一个免费网页模板下载
  7. 赶集网怒吼58同城 被刺痛了么?
  8. springboot打成Jar包下载Excel模板文件损坏问题
  9. hive中round、floor、ceil区别及用法
  10. 5.2 VLAN:QinQ