首页 > 其他分享 >SpringBoot事件和监听器

SpringBoot事件和监听器

时间:2023-10-30 18:55:18浏览次数:37  
标签:context SpringBoot -- boot springframework 事件 监听器 org event

事件和监听器

生命周期监听

场景:监听应用的生命周期

监听器-SpringApplicationRunListener

  1. 自定义SpringApplicationRunListener来监听事件;
    1.1. 编写SpringApplicationRunListener 实现类
    1.2. 在 META-INF/spring.factories 中配置 org.springframework.boot.SpringApplicationRunListener=自己的Listener,还可以指定一个有参构造器,接受两个参数(SpringApplication application, String[] args)
    1.3. springboot 在spring-boot.jar中配置了默认的 Listener,如下

org\springframework\boot\spring-boot\3.1.5\spring-boot-3.1.5.jar!\META-INF\spring.factories

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
/**
 * Listener先要从 META-INF/spring.factories 读到
 *
 * 1、引导: 利用 BootstrapContext 引导整个项目启动
 *      starting:              应用开始,SpringApplication的run方法一调用,只要有了 BootstrapContext 就执行
 *      environmentPrepared:   环境准备好(把启动参数等绑定到环境变量中),但是ioc还没有创建;【调一次】
 * 2、启动:
 *      contextPrepared:       ioc容器创建并准备好,但是sources(主配置类)没加载。并关闭引导上下文;组件都没创建  【调一次】
 *      contextLoaded:         ioc容器加载。主配置类加载进去了。但是ioc容器还没刷新(我们的bean没创建)。
 *      =======截止以前,ioc容器里面还没造bean呢=======
 *      started:               ioc容器刷新了(所有bean造好了),但是 runner 没调用。
 *      ready:                  ioc容器刷新了(所有bean造好了),所有 runner 调用完了。
 * 3、运行
 *     以前步骤都正确执行,代表容器running。
 */

生命周期全流程

事件触发时机

各种回调监听器

  • BootstrapRegistryInitializer: 感知特定阶段:感知引导初始化
    • META-INF/spring.factories
    • 创建引导上下文bootstrapContext的时候触发。
    • application.addBootstrapRegistryInitializer();
    • 场景:进行密钥校对授权。
  • ApplicationContextInitializer: 感知特定阶段: 感知ioc容器初始化
    • META-INF/spring.factories
    • application.addInitializers();
  • ApplicationListener: 感知全阶段:基于事件机制,感知事件。 一旦到了哪个阶段可以做别的事
    • @Bean或@EventListener: 事件驱动
    • SpringApplication.addListeners(…)SpringApplicationBuilder.listeners(…)
    • META-INF/spring.factories
  • SpringApplicationRunListener: 感知全阶段生命周期 + 各种阶段都能自定义操作; 功能更完善。
    • META-INF/spring.factories
  • ApplicationRunner: 感知特定阶段:感知应用就绪Ready。卡死应用,就不会就绪
    • @Bean
  • CommandLineRunner: 感知特定阶段:感知应用就绪Ready。卡死应用,就不会就绪
    • @Bean

最佳实战:

  • 如果项目启动前做事: BootstrapRegistryInitializer 和 ApplicationContextInitializer
  • 如果想要在项目启动完成后做事:ApplicationRunner和 CommandLineRunner
  • 如果要干涉生命周期做事:SpringApplicationRunListener
  • 如果想要用事件机制:ApplicationListener

完整触发流程

9大事件触发顺序&时机

  1. ApplicationStartingEvent:应用启动但未做任何事情, 除过注册listeners and initializers.
  2. ApplicationEnvironmentPreparedEvent: Environment 准备好,但context 未创建.
  3. ApplicationContextInitializedEvent: ApplicationContext 准备好,ApplicationContextInitializers 调用,但是任何bean未加载
  4. ApplicationPreparedEvent: 容器刷新之前,bean定义信息加载
  5. ApplicationStartedEvent: 容器刷新完成, runner未调用
    ---以下就开始插入了探针机制---
  6. AvailabilityChangeEventLivenessState.CORRECT应用存活; 存活探针
  7. ApplicationReadyEvent: 任何runner被调用
  8. AvailabilityChangeEventReadinessState.ACCEPTING_TRAFFIC就绪探针,可以接请求
  9. ApplicationFailedEvent :启动出错

应用事件发送顺序如下:

感知应用是否存活了:可能植物状态,虽然活着但是不能处理请求。
应用是否就绪了:能响应请求,说明确实活的比较好。

代码使用SpringApplicationRunListenerApplicationListener

/resource/META-INF/spring.factories

org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.boot3.core.listener.MyApplicationListener

org.springframework.context.ApplicationListener=\
com.atguigu.boot3.core.listener.MyEventListener

MyApplicationListener.java

用来感知SpringBoot生命周期

package com.atguigu.boot3.core.listener;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import java.time.Duration;

/**
 * SpringBoot的生命周期
 */
@Slf4j
public class MyApplicationListener implements SpringApplicationRunListener {

    /**
     * 在run方法首次启动时立即调用。可以用于非常早期的初始化。
     */
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("***starting***");
    }

    /**
     * 环境准备好就会调用,但是在 ApplicationContext 创建前
     */
    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("***environmentPrepared***");
    }

    /**
     * ApplicationContext已经被创建,但是还未加载
     */
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("***contextPrepared***");
    }

    /**
     * 在ApplicationContext加载后但在刷新之前调用
     */
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("***contextLoaded***");
    }

    /**
     * ApplicationContext已经刷新,但是CommandLineRunners和ApplicationRunners还未被调用
     */
    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("***started***");
    }

    /**
     * 在调用了CommandLineRunners和ApplicationRunners后,ApplicationContext容器run方法运行之前运行
     */
    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("***ready***");
    }

    /**
     * 在应用程序运行出错时运行
     */
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("***failed***");
    }
}

MyEventListener.java
监听事件

package com.atguigu.boot3.core.listener;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class MyEventListener implements ApplicationListener<ApplicationEvent> {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("--[event]--" + event.getClass().getName());
    }
}

运行结果

E:\Java\jdk-17.0.5\bin\java.exe ...

--[event]--org.springframework.boot.context.event.ApplicationStartingEvent
***starting***
--[event]--org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent
***environmentPrepared***

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.1.5)

--[event]--org.springframework.boot.context.event.ApplicationContextInitializedEvent
***contextPrepared***
2023-10-30T18:08:56.239+08:00  INFO 16448 --- [           main] com.atguigu.boot3.core.MainApplication   : Starting MainApplication using Java 17.0.5 with PID 16448 (E:\code\IdeaProjects\spring-boot-3\boot3-07-core\target\classes started by 朱俊伟 in E:\code\IdeaProjects\spring-boot-3)
2023-10-30T18:08:56.242+08:00  INFO 16448 --- [           main] com.atguigu.boot3.core.MainApplication   : The following 1 profile is active: "dev"
--[event]--org.springframework.boot.context.event.ApplicationPreparedEvent
***contextLoaded***
2023-10-30T18:08:57.269+08:00  INFO 16448 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2023-10-30T18:08:57.281+08:00  INFO 16448 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-10-30T18:08:57.281+08:00  INFO 16448 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.15]
2023-10-30T18:08:57.367+08:00  INFO 16448 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-10-30T18:08:57.368+08:00  INFO 16448 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1064 ms
2023-10-30T18:08:57.765+08:00  INFO 16448 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
--[event]--org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent
--[event]--org.springframework.context.event.ContextRefreshedEvent
2023-10-30T18:08:57.774+08:00  INFO 16448 --- [           main] com.atguigu.boot3.core.MainApplication   : Started MainApplication in 2.248 seconds (process running for 2.97)
--[event]--org.springframework.boot.context.event.ApplicationStartedEvent
--[event]--org.springframework.boot.availability.AvailabilityChangeEvent
***started***
--[event]--org.springframework.boot.context.event.ApplicationReadyEvent
--[event]--org.springframework.boot.availability.AvailabilityChangeEvent
***ready***
--[event]--org.springframework.boot.availability.AvailabilityChangeEvent
--[event]--org.springframework.context.event.ContextClosedEvent

参考:
https://www.yuque.com/leifengyang/springboot3/lliphvul8b19pqxp#beI2B

标签:context,SpringBoot,--,boot,springframework,事件,监听器,org,event
From: https://www.cnblogs.com/zjw-blog/p/17798565.html

相关文章

  • [Springboot整合thymeleaf]处理js中的路径问题。
    使用了thymeleaf模板引擎之后,html中的标签,都可以直接替换成th:srcth:href但是处理js的中的资源路径并不是像jsp那么简单了。可以通过以下方式解决。<!--处理路径问题--><scriptth:inline="javascript">varpath=[[${#request.contextPath}]]</script><scriptth:inl......
  • 34-Vue脚手架-组件的自定义事件(使用自定义事件优化Todo-List案例)
    组件的自定义事件1.一种组件间通信的方式,适用于子组件===>父组件(这里也可以使用props传递数据进行实现)2.使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)3.绑定自定义事件:1)第一种方式,在父组件中<!--通过父组件给子组件绑定一个......
  • 极速指南:在 SpringBoot 中快速集成腾讯云短信功能
    前言今天分享一个SpringBoot集成腾讯云短信的功能,平常除了工作,很多xdm做自己的小项目都可能用到短信,但自己去看文档挺费劲的,我这边就帮你节省时间,直接把步骤给你列出来,照做就行。实战1、申请密钥及签名模板首先,要使用腾讯云短信,你得先在腾讯云有个账号,申请密钥及签名模板。1)......
  • PHP全院级不良事件管理系统源码,支持上报、处理、分析、整改
    不良事件管理系统帮助医院梳理建立不良事件上报与管理的一体化解决方案,包含上报内容、归口科室、上报流程及管理办法。提供面向医院的不良事件全过程管理平台,包含事件上报、事件处理、事件追踪、RCA分析及持续改进等环节,帮助管理者从医院管理体系、运行机制与规章制度上进行有针对......
  • 使用RxJava实现多次连续点击的事件监听
    说起响应试编程,要提到的当然是Rx系列的库了,Rx系列的库对于很多语言和平台的运用是非常广泛的,例如(.NET,Java,Scala,Clojure,JavaScript,Ruby,Python,C++,Objective-C/Cocoa,Groovy等等。而本篇将会记录如何使用RxJava对Android点击事件的监听以异步数据流的方式来进行处理,......
  • SpringBoot——SSM简单整合v0.1
    学习SpringBoot初次整合SSM,后续需要不断优化参考SpringBoot3教程[1]导入依赖pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"......
  • 聊聊昨日ChatGPT全球宕机事件,带给我们的警示
    作者|卖萌酱,王二狗昨日,ChatGPT崩了!许多人发现无论是ChatGPT或是ChatGPTPLUS都不能正常工作了。还连带了全球数以万计的依赖ChatGPTAPI的热门AI应用也纷纷崩溃。有Twitter网友调侃到,昨日受ChatGPT宕机的影响,全球的生产力下降了50%,打工人一片哀嚎。更有网友上传了一段视频,真......
  • 浅析SpringBoot加载配置的6种方式
    从配置文件中获取属性应该是SpringBoot开发中最为常用的功能之一,但就是这么常用的功能,仍然有很多开发者抓狂~今天带大家简单回顾一下这六种的使用方式:说明Environment对象Environment是springboot核心的环境配置接口,它提供了简单的方法来访问应用程序属性,包括系统属......
  • SpringBoot3特性——错误信息Problemdetails
    SpringFramework6实现了HTTPAPI规范RFC7807的问题详细信息。在本文中,我们将学习如何在SpringBoot3RESTAPI(使用SpringFramework6)中处理异常,并使用ProblemDetailsAPI提供错误响应。详见https://www.sivalabs.in/spring-boot-3-error-reporting-using-proble......
  • springboot Filter @Resource 为空 、@Value 无法读取yml配置的问题
    问题1:在过滤器中使用@Resource为nullSpring中,web应用启动的顺序是:listener->filter->servlet,先初始化listener,然后再来就filter的初始化,再接着才到我们的dispathServlet的初始化,因此,当我们需要在filter里注入一个注解的bean时,就会注入失败,因为filter初始化时,注解的bean还没初......