当前位置: 首页 > article >正文

spring-boot自定义ApplicationListener及源码分析

ApplicationListener是spring boot应用启动时的事件监听器。监听的事件有(包括但不限于):

(1)接下来,我们先通过一个例子实现自定义ApplicationListener:

监听器需要实现ApplicationListener<T>,参数类型为ApplicationEvent,表示监听所有事件,当然也可以将参数类型设置为单独的事件,下面这个只会接收ApplicationEnvironmentPreparedEvent事件:

(2)定义了监听器后,还需要配置一下,让spring boot启动时加载它,即配置"context.listener.classes"

(3)启动后可以看到,监听器监听了如下事件:

(4)源码分析,我们来看看自定义的监听器是怎么工作的:

ApplicationListener是采用观察者模式实现的,我们的启动时入口是执行SpringApplication.run方法

如下两处代码,分别是获取SpringApplicationRunListeners(这个是各个事件的发布者)和进行环境的准备,

在环境准备好后发布ApplicationEnvironmentPreparedEvent事件

虽然这里listeners是容器类,但默认只有一个EventPublishingRunListener,我们看一下它是怎么发布事件的,如下代码很明显,进行了一个事件的广播,但还没看到广播给谁,继续往下

这里可以看到getApplicationListeners(event, type),就是根据事件类型获取需要广播的ApplicationListener

在调试状态下,我们看一下getApplicationListeners(event, type)有哪些

发现只有6个ApplicationListener响应了ApplicationEnvironmentPreparedEvent事件,而且没有我们自定义的ApplicationListener,怎么回事呢?

实际上,我们的ApplicationListener是通过代理类执行的,即上面的DelegatingApplicationListener,我们可以看一下它怎么执行的:

上面代码可以看到代理类也监听了所有的事件,然后在ApplicationEnvironmentPreparedEvent事件时才初次响应,并且通过getListeners获取所有代理的ApplicationListeners,然后它自己实现了一个事件广播器,然后把获取的ApplicationListeners通过到addApplicationListener加入到广播器中,最后进行事件的广播转发。我们重点看一下getListeners,看是如何获取到我们自定义的ApplicationListeners的:

我们可以看到,是通过我们配置的context.listener.classes获得类名,然后通过反射实例化返回。

这样整个监听器的过程就完整了。我们注意到代理类是从ApplicationEnvironmentPreparedEvent开始响应的,所以之前的事件我们自定义的ApplicationListener是无法监听的。实际上前面只有一个ApplicationStartingEvent,此时应用才刚启动,也没啥好监听的。如果需要监听所有的事件可以在自己在spring.factories配置:

在resources下新建META-INF\spring.factoies,然后和spring的监听器配置一样配置自己定义的监听器,就可以啦


http://www.kler.cn/a/417967.html

相关文章:

  • Rust学习笔记_07——枚举和范围
  • ceph 报错 crush rule 20 type does not match pool
  • js原型、原型链和继承
  • MacOS 如何连接 Linux NFS 服务器
  • 排序算法2
  • [Java]微服务配置管理
  • SVN迁移至Git,保留commit提交记录
  • 使用Spring Data MongoDB中的MongoTemplate实现分组查询最新的数据
  • 设计模式---建造者模式
  • 迅为RK3588开发板Android12源码定制开发-安装adb驱动
  • 飙升Vue.js组件开发
  • Flutter 1.1:下载Flutter环境
  • 一个鸿蒙开发者的探索:实现相册访问功能
  • Python+Pytest+Yaml+Allure数据参数化(DDT)数据驱动(一)
  • 前端css实例
  • 【04】Selenium+Python 手动添加Cookie免登录(实例)
  • 何时在 SQL 中使用 CHAR、VARCHAR 和 VARCHAR(MAX)
  • Golang context 的作用和实现原理
  • 7. 现代卷积神经网络
  • 【051】基于51单片机温度计【Proteus仿真+Keil程序+报告+原理图】
  • uni-app获取到的数据如何保留两位小数
  • JavaWeb开发 : tomcat+Servlet+JSP
  • Mac苹果电脑 java前后端开发环境及软件安装教程
  • 算法编程题-煎饼排序 不含AAA或者BBB的字符串
  • Jtti:排查和解决服务器死机问题的步骤
  • LangChain——HTML文本分割 多种文本分割