一.知识回顾
【0.SpringBoot专栏的相关文章都在这里哟,后续更多的文章内容可以点击查看】
【1.SpringBoot初识之Spring注解发展流程以及常用的Spring和SpringBoot注解】
【2.SpringBoot自动装配之SPI机制&SPI案例实操学习&SPI机制核心源码学习】
【3.详细学习SpringBoot自动装配原理分析之核心流程初解析-1】
【4.详细学习SpringBoot自动装配原理之自定义手写Starter案例实操实战-2】
【5.IDEA中集成SpringBoot源码环境详细步骤讲解】
【6.初识SpringBoot核心源码之SpringApplication构造器以及run方法主线流程-3】
【7.详细学习SpringBoot核心源码之SpringApplication构造器&Run方法源码详细流程-4】
二.观察者设计模式
在学习SpringBoot源码的监听器之前,我们必须提前学习一下观察者设计模式,观察者设计模式在我之前写过的设计模式专栏中详细讲解过,大家先去学习一下观察者设计模式,然后我们再来学习一下SpringBoot监听器就会更加明白了。话不多说,上链接。
【Java中23种面试常考的设计模式之观察者模式(Observer)---行为型模式】
下面这几句话很重要:
发布器相当于是观察者设计模式当中的主题,监听器listener相当于是观察者设计模式当中的observer,每一个listener用来监听不同的事件。
发布器中有一个集合专门用来存储所有的listener,发布器发布事件的本质就是遍历属性集合,执行每一个listener中的onApplicationEvent()方法。
三.SpringBoot源码之监听器设计
3.1 初始化并加载监听器
之前的文章我们学习过在SpringApplication的构造方法中会加载所有声明在spring.factories中的监听器。
SpringApplication中初始化并加载所有监听器的核心逻辑代码
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 传递的resourceLoader为null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 记录主方法的配置类名称
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 记录当前项目的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 加载配置在spring.factories文件中的ApplicationContextInitializer对应的类型并实例化
// 并将加载的数据存储在了 initializers 成员变量中。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 初始化监听器 并将加载的监听器实例对象存储在了listeners成员变量中
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 反推main方法所在的Class对象 并记录在了mainApplicationClass对象中
this.mainApplicationClass = deduceMainApplicationClass();
}
setListeners为核心方法
通过debug我们可以知道加载的监听器就是key为ApplicationListener.class的所有监听器,默认加载的11个监听器
3.2 SpringApplication.run()方法中获取所有发布事件的发布器
核心方法getRunListeners
run方法中获取事件发布器的方法getRunListeners()
进入getRunListeners方法
进入getSpringFactoriesInstances方法,并传入SpringApplicationRunListener.class类对象
spring.factories文件中对应的SpringApplicationRunListener事件发布器
实例化操作就会执行EventPublishingRunListener.
回退并进入SpringApplicationRunListeners方法,将从配置文件中加载的集合放入到属性集合当中去。
接下来就是一个小转折,发布器发布事件,监听器监听到发布的事件并作出相关的逻辑操作
首先我们学习的就是项目启动后,发布器发布事件的主入口方法
进入starting方法,挨个遍历我们的发布器,并去发布相关的事件
进入其中的重载构造方法,starting()
再进入它的实现方法。
然后再进入multicastEvent方法,传入ApplicationStartingEvent类型的事件
然后执行重载的方法,监听器的同步和异步调用,我们可以看到具体的触发逻辑
继续进入invokeListener方法,查看具体逻辑
需要继续进入doInvokeListener方法,查看具体逻辑操作。
学源码必须刨根问题,所以我们需要进入到ApplicationListener接口一探究竟。
跟到这里,后面的事件发布与监听器的处理逻辑就差不多是一致了。到这儿对应SpringBoot中的监听器这块就分析的差不多了。下篇文章我们将要学习的就是SpringBoot的核心配置文件,SpringBoot的属性文件中的信息什么时候加载的就是在这些内置的监听器中完成的。
四.SpringBoot中默认的监听器以及默认的事件类型
4.1 SpringBoot中默认的监听器
SpringBoot中给我们提供的默认的监听器,这些都定义在spring.factories文件中。
监听器 | 监听事件 | 说明 |
---|---|---|
ClearCachesApplicationListener | ContextRefreshedEvent | 当触发ContextRefreshedEvent事件会清空应用的缓存 |
ParentContextCloserApplicationListener | ParentContextAvailableEvent | 触发ParentContextAvailableEvent事件会完成父容器关闭的监听器 |
CloudFoundryVcapEnvironmentPostProcessor | ApplicationPreparedEvent | 判断环境中是否存在VCAP_APPLICATION或者VCAP_SERVICES。如果有就添加Cloud Foundry的配置;没有就不执行任何操作。 |
FileEncodingApplicationListener | ApplicationEnvironmentPreparedEvent | 文件编码的监听器 |
AnsiOutputApplicationListener | ApplicationEnvironmentPreparedEvent | 根据 spring.output.ansi.enabled 参数配置 AnsiOutput |
ConfigFileApplicationListener | ApplicationEnvironmentPreparedEvent <br> ApplicationPreparedEvent | 完成相关属性文件的加载,application.properties application.yml 前面源码内容详细讲解过 |
DelegatingApplicationListener | ApplicationEnvironmentPreparedEvent | 监听到事件后转发给环境变量 context.listener.classes 指定的那些事件监听器 |
ClasspathLoggingApplicationListener | ApplicationEnvironmentPreparedEvent <br> ApplicationFailedEvent | 一个SmartApplicationListener,对环境就绪事件ApplicationEnvironmentPreparedEvent/应用失败事件ApplicationFailedEvent做出响应,往日志DEBUG级别输出TCCL(thread context class loader)的classpath。 |
LoggingApplicationListener | ApplicationStartingEvent <br> ApplicationEnvironmentPreparedEvent <br> ApplicationPreparedEvent <br> ContextClosedEvent <br> ApplicationFailedEvent | 配置 LoggingSystem 。使用 logging.config 环境变量指定的配置或者缺省配置 |
LiquibaseServiceLocatorApplicationListener | ApplicationStartingEvent | 使用一个可以和Spring Boot可执行jar包配合工作的版本替换liquibase ServiceLocator |
BackgroundPreinitializer | ApplicationStartingEvent <br> ApplicationReadyEvent <br> ApplicationFailedEvent | 尽早触发一些耗时的初始化任务,使用一个后台线程 |
4.2 SpringBoot中默认的事件
SpringBoot中的所有的事件都是继承于 ApplicationEvent
这个抽象类,在SpringBoot启动的时候会发布如下的相关事件,而这些事件其实都实现了 SpringApplicationContext
接口。
事件 | 说明 |
---|---|
ApplicationStartingEvent | 容器启动的事件 |
ApplicationEnvironmentPreparedEvent | 应用处理环境变量相关的事件 |
ApplicationContextInitializedEvent | 容器初始化的事件 |
ApplicationPreparedEvent | 应用准备的事件 |
ApplicationFailedEvent | 应用启动出错的事件 |
ApplicationStartedEvent | 应用Started状态事件 |
ApplicationReadyEvent | 应用准备就绪的事件 |
这些事件都是属于SpringBoot启动过程中涉及到的相关的事件
好了,本篇文章【详细学习SpringBoot核心源码之监听器原理-5(观察者设计模式、初始化并加载监听器核心流程、事件的发布器核心流程、SpringBoot中默认的监听器以及默认的事件类型)】到学习到这里,下篇文章我们将先来学习一下自定义监听器的实现过程,然后再来学习配置文件的核心流程。