SpringBoot内置生命周期事件详解 SpringBoot源码(十)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot内置生命周期事件详解 SpringBoot源码(十)相关的知识,希望对你有一定的参考价值。
参考技术ASpringBoot中文注释项目Github地址:
https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE
本篇接 SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)
温故而知新,我们来简单回顾一下上篇的内容,上一篇我们分析了 SpringBoot启动时广播生命周期事件的原理 ,现将关键步骤再浓缩总结下:
上篇文章的侧重点是分析了SpringBoot启动时广播生命周期事件的原理,此篇文章我们再来详细分析SpringBoot内置的7种生命周期事件的源码。
分析SpringBoot的生命周期事件,我们先来看一张类结构图:
由上图可以看到事件类之间的关系:
EventObject 类是JDK的事件基类,可以说是所有Java事件类的基本,即所有的Java事件类都直接或间接继承于该类,源码如下:
可以看到 EventObject 类只有一个属性 source ,这个属性是用来记录最初事件是发生在哪个类,举个栗子,比如在SpringBoot启动过程中会发射 ApplicationStartingEvent 事件,而这个事件最初是在 SpringApplication 类中发射的,因此 source 就是 SpringApplication 对象。
ApplicationEvent 继承了DK的事件基类 EventObject 类,是Spring的事件基类,被所有Spring的具体事件类继承,源码如下:
可以看到 ApplicationEvent 有且仅有一个属性 timestamp ,该属性是用来记录事件发生的时间。
SpringApplicationEvent 类继承了Spring的事件基类 ApplicationEvent ,是所有SpringBoot内置生命周期事件的父类,源码如下:
可以看到 SpringApplicationEvent 有且仅有一个属性 args ,该属性就是SpringBoot启动时的命令行参数即标注 @SpringBootApplication 启动类中 main 函数的参数。
接下来我们再来看一下 SpringBoot 内置生命周期事件即 SpringApplicationEvent 的具体子类们。
SpringBoot开始启动时便会发布 ApplicationStartingEvent 事件,其发布时机在环境变量Environment或容器ApplicationContext创建前但在注册 ApplicationListener 具体监听器之后,标志标志 SpringApplication 开始启动。
可以看到 ApplicationEnvironmentPreparedEvent 事件多了一个 environment 属性,我们不妨想一下,多了 environment 属性的作用是啥?
答案就是 ApplicationEnvironmentPreparedEvent 事件的 environment 属性作用是利用事件发布订阅机制,相应监听器们可以从 ApplicationEnvironmentPreparedEvent 事件中取出 environment 变量,然后我们可以为 environment 属性增加属性值或读出 environment 变量中的值。
当SpringApplication已经开始启动且环境变量 Environment 已经创建后,并且为环境变量 Environment 配置了命令行和 Servlet 等类型的环境变量后,此时会发布 ApplicationEnvironmentPreparedEvent 事件。
监听 ApplicationEnvironmentPreparedEvent 事件的第一个监听器是 ConfigFileApplicationListener ,因为是 ConfigFileApplicationListener 监听器还要为环境变量 Environment 增加 application.properties 配置文件中的环境变量;此后还有一些也是监听 ApplicationEnvironmentPreparedEvent 事件的其他监听器监听到此事件时,此时可以说环境变量 Environment 几乎已经完全准备好了。
可以看到 ApplicationContextInitializedEvent 事件多了个 ConfigurableApplicationContext 类型的 context 属性, context 属性的作用同样是为了相应监听器可以拿到这个 context 属性执行一些逻辑,具体作用将在 3.4.4 详述。
ApplicationContextInitializedEvent 事件在 ApplicationContext 容器创建后,且为 ApplicationContext 容器设置了 environment 变量和执行了 ApplicationContextInitializers 的初始化方法后但在bean定义加载前触发,标志ApplicationContext已经初始化完毕。
同样可以看到 ApplicationPreparedEvent 事件多了个 ConfigurableApplicationContext 类型的 context 属性,多了 context 属性的作用是能让监听该事件的监听器们能拿到 context 属性,监听器拿到 context 属性一般有如下作用:
ApplicationPreparedEvent 事件在 ApplicationContext 容器已经完全准备好时但在容器刷新前触发,在这个阶段 bean 定义已经加载完毕还有 environment 已经准备好可以用了。
ApplicationStartedEvent 事件将在容器刷新后但 ApplicationRunner 和 CommandLineRunner 的 run 方法执行前触发,标志 Spring 容器已经刷新,此时容器已经准备完毕了。
ApplicationReadyEvent 事件在调用完 ApplicationRunner 和 CommandLineRunner 的 run 方法后触发,此时标志 SpringApplication 已经正在运行。
可以看到 ApplicationFailedEvent 事件除了多了一个 context 属性外,还多了一个 Throwable 类型的 exception 属性用来记录SpringBoot启动失败时的异常。
ApplicationFailedEvent 事件在SpringBoot启动失败时触发,标志SpringBoot启动失败。
此篇文章相对简单,对SpringBoot内置的7种生命周期事件进行了详细分析。我们还是引用上篇文章的一张图来回顾一下这些生命周期事件及其用途:
由于有一些小伙伴们建议之前有些源码分析文章太长,导致耐心不够,看不下去,因此,之后的源码分析文章如果太长的话,笔者将会考虑拆分为几篇文章,这样就比较短小了,比较容易看完,嘿嘿。
【源码笔记】Github地址:
https://github.com/yuanmabiji/Java-SourceCode-Blogs
点赞搞起来,嘿嘿嘿!
公众号【 源码笔记 】专注于Java后端系列框架的源码分析。
Springboot生命周期
ApplicationContextInitializedEvent
当 SpringApplication 启动并且准备好 ApplicationContext,并且在加载任何 bean 定义之前调用了 ApplicationContextInitializers 时发布的事件。对应的生命周期方法是contextPrepared()
ApplicationPreparedEvent
ApplicationPreparedEvent 是SpringBoot上下文 context 创建完成是发布的事件;但此时 spring 中的 bean 还没有完全加载完成。这里可以将上下文传递出去做一些额外的操作。但是在该监听器中是无法获取自定义 bean 并进行操作的。对应的生命周期方法是 contextLoaded()。
ApplicationStartedEvent
这个事件是在 2.0 版本才引入的;具体发布是在应用程序上下文刷新之后,调用任何 ApplicationRunner 和 CommandLineRunner 运行程序之前。
SpringApplicationRunListeners
SpringApplicationRunListeners 是一个集合类,内部包含一个 log 和包含 SpringApplicationRunListener 的 List。而 SpringApplicationRunListener 主要是监听 SpringApplication 对象的,里面的方法都定义了在何时调用 SpringApplicationRunListener 的各种方法,它的实现类是EventPublishingRunListener。它就是一个ApplicationListener的代理。springboot启动的几个主要过程的监听通知都是通过他来进行回调,它的生命周期就是从开始启动,到启动结束。
下面的每一个方法 SpringApplicationRunListener 都把其包装成一个事件,在spring容器还未成功 refreshed 之前都是使用SimpleApplicationEventMulticaster 去寻找对该事件感兴趣的ApplicationListener,然后调用其onApplicationEvent方法
starting:当SpringApplication对象的run方法刚启动的时候(依靠SimpleApplicationEventMulticaster)
environmentPrepared:在environment Prepared 但是spring容器还未创建的时候(依靠SimpleApplicationEventMulticaster)
contextPrepared:当spring容器已经创建且准备好了,(目前是空的实现)
contextLoaded:当spring容器已经loaded 且未refresh 。load就是将我们的primaryClass注册到spring容器中,(依靠SimpleApplicationEventMulticaster) 同时将之前获取到的ApplicationListener都加入到spring容器中,此时如果ApplicationListener还是ApplicationContextAware的也要调用其setApplicationContext方法。
started:spring容器已经刷新过且应用已经启动,但是CommandLineRunners和ApplicationRunners还未调用,直接通过spring容器自己发送(因为ApplicationListener已经加入spring容器)
running:我们已经调用了CommandLineRunners,直接通过spring容器自己发送(因为ApplicationListener已经加入spring容器)
failed:当异常发生的时候就调用这个,如果spring容器没有loaded 或者没有激活就使用SimpleApplicationEventMulticaster,否则还是依靠spring容器自己。
以上是关于SpringBoot内置生命周期事件详解 SpringBoot源码(十)的主要内容,如果未能解决你的问题,请参考以下文章