重学SpringBoot3-SpringApplicationRunListener

重学SpringBoot3-SpringApplicationRunListener

CoderJia 13 2024-09-13

SpringApplicationRunListener 是 Spring Boot 框架中的一个接口,主要用于监听 Spring Boot 应用启动过程中的不同阶段。通过实现这个接口,开发者可以在应用启动的过程中插入自定义的逻辑,例如在启动前进行某些预处理、修改应用上下文,甚至在启动失败时做出相应的处理。

在 Spring Boot 3 中,SpringApplicationRunListener 保持了其核心功能,并且随着 Spring 框架的进化,提供了一些更灵活的应用配置和启动定制化支持。

1. 基本作用

SpringApplicationRunListener 作为一个监听器接口,提供了多个钩子方法来捕捉应用启动的各个阶段。Spring Boot 应用启动过程中大致包含以下几个步骤:

  1. 准备环境(EnvironmentPrepared):在读取应用程序配置、解析命令行参数后,准备运行环境。
  2. 准备上下文(ContextPrepared):在应用上下文被创建并准备好但尚未刷新时。
  3. 上下文加载完成(ContextLoaded):在应用上下文加载完成但还未启动时。
  4. 上下文启动(Started):应用上下文刷新并启动。
  5. 运行完成(Running/Ready):整个应用完全启动并准备处理请求。
  6. 启动失败(Failed):应用在启动过程中发生错误或异常。

通过实现 SpringApplicationRunListener,可以在这些关键步骤之间插入自定义逻辑,以扩展和控制应用的启动行为。

2. 如何实现

要自定义 SpringApplicationRunListener,需要:

  1. 实现接口:创建一个类实现 SpringApplicationRunListener 接口。
  2. 注册监听器:在 META-INF/spring.factories 文件中注册自定义的监听器类。

2.1. 创建 SpringApplicationRunListener

首先,创建一个类并实现 SpringApplicationRunListener 接口:

SpringBoot2.6以上版本

package com.coderjia.boot.confi;

import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import java.time.Duration;

/**
 * @author CoderJia
 * @create 2024/09/13 15:41
 * @Description
 **/
public class CustomSpringApplicationRunListener implements SpringApplicationRunListener {

    public CustomSpringApplicationRunListener(SpringApplication application, String[] args) {
        // 必须定义这个构造方法,以便 Spring 能正确初始化这个监听器
    }

    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("应用正在启动:starting()");
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("环境已经准备好:environmentPrepared()");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("上下文已准备:contextPrepared()");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("上下文已加载:contextLoaded()");
    }

    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("应用已启动!启动耗时:" + timeTaken.toMillis() + " 毫秒");
    }

    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("应用已准备就绪!启动耗时:" + timeTaken.toMillis() + " 毫秒");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("应用启动失败:failed()");
    }
}

每个方法代表应用启动的一个关键阶段,开发者可以在这些方法中插入自定义逻辑,如日志记录、性能监控或额外的资源加载。

SpringBoot2.6之前版本

SpringBoot2.6以上版本主要是用running 方法被替换为 ready 方法,started 方法现在也接收一个额外的 Duration timeTaken 参数。

为什么替换 runningready

Spring Boot 团队在 2.6.0 版本中做出这一修改的目的是为了更加精确地表示应用启动完成的状态。running 方法的名称虽然也表示应用已经启动,但它并没有表达出应用已经完全准备好处理外部请求的意思。相反,ready 方法名称更明确,表示应用已经达到可用状态。另外,Duration 参数为开发者提供了额外的信息,能够监控启动时间。这对生产环境下的性能调优和监控非常有帮助。

startedready 的区别

在 Spring Boot 的应用生命周期中,started 方法表示应用上下文已经刷新并完全启动,此时 Bean 已经加载完成,ApplicationContext 已经初始化和准备好。和 ready 方法的区别是,started 标志着应用在完成上下文刷新之后,还没有完全准备好处理外部请求,而 ready 是表示应用进入可以处理请求的状态。通过添加 Duration timeTaken 参数,开发者可以记录应用从启动到上下文准备完成的时间,这对于分析应用启动阶段的性能非常有帮助。

2.2. 注册 SpringApplicationRunListener

要使 Spring Boot 能够发现并使用自定义的监听器,需要在 META-INF/spring.factories 文件中进行注册。确保该文件位于 resources 目录下,内容如下:

org.springframework.boot.SpringApplicationRunListener=\
com.coderjia.boot.confi.CustomSpringApplicationRunListener

spring.factories配置

这个配置会告诉 Spring Boot 在启动时加载并使用自定义的 SpringApplicationRunListener 实现。

2.3. 完整示例

新建一个 Spring Boot 项目,在项目中,我们希望在启动的每个阶段输出日志,确保启动过程中的每个步骤都清晰可见。以下是一个完整的代码示例:

启动 Spring Boot 应用时,就会在控制台中看到每个启动阶段的日志输出。

演示

3. 适用场景

SpringApplicationRunListener 的使用场景包括但不限于:

  • 启动日志记录:可以精确记录应用的启动过程,便于后续的性能分析和调优。
  • 环境变量配置:在 environmentPrepared 阶段,可以动态调整环境变量的值。
  • 启动故障处理:在 failed 方法中处理启动失败后的逻辑,比如发送通知或日志存储。
  • 条件化启动逻辑:可以根据不同的条件,在启动过程中启用或禁用特定的功能。

4. 总结

SpringApplicationRunListener 提供了一个强大的机制,用于在 Spring Boot 应用启动的多个关键阶段插入自定义逻辑。在 Spring Boot 3 中,这个接口依旧是扩展应用启动流程的有效方式。通过合理使用 SpringApplicationRunListener,开发者可以更加灵活地控制应用的启动行为,并为复杂的启动场景提供解决方案。希望这篇文章能够帮助你更好地理解和使用 SpringApplicationRunListener