SpringApplication

SpringApplication 类提供了一种便捷的方式来启动从 main() 方法开始的 Spring 应用程序。 在许多情况下,您可以委托给静态的 SpringApplication.run(Class, String…​) 方法,如下例所示:

  • Java

  • Kotlin

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class, args);
	}

}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication


@SpringBootApplication
class MyApplication

fun main(args: Array<String>) {
	runApplication<MyApplication>(*args)
}

当您的应用程序启动时,您应该会看到类似于以下内容的输出:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.5.0)

2025-05-26T18:13:11.232+08:00  INFO 40550 --- [           main] o.s.b.d.f.logexample.MyApplication       : Starting MyApplication using Java 21.0.7 with PID 40550 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2025-05-26T18:13:11.234+08:00  INFO 40550 --- [           main] o.s.b.d.f.logexample.MyApplication       : No active profile set, falling back to 1 default profile: "default"
2025-05-26T18:13:11.836+08:00  INFO 40550 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2025-05-26T18:13:11.856+08:00  INFO 40550 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-05-26T18:13:11.857+08:00  INFO 40550 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.41]
2025-05-26T18:13:11.901+08:00  INFO 40550 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-05-26T18:13:11.903+08:00  INFO 40550 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 635 ms
2025-05-26T18:13:12.281+08:00  INFO 40550 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-05-26T18:13:12.290+08:00  INFO 40550 --- [           main] o.s.b.d.f.logexample.MyApplication       : Started MyApplication in 1.369 seconds (process running for 1.528)
2025-05-26T18:13:12.296+08:00  INFO 40550 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete

默认情况下,会显示 INFO 日志消息,包括一些相关的启动详细信息,例如启动应用程序的用户。 如果您需要除 INFO 之外的其他日志级别,可以按照 日志级别 中描述的方式进行设置。 应用程序版本通过主应用程序类的包的实现版本来确定。 可以通过将 spring.main.log-startup-info 设置为 false 来关闭启动信息日志记录。 这也将关闭应用程序活动配置文件的日志记录。

要在启动期间添加额外的日志记录,您可以在 SpringApplication 的子类中重写 logStartupInfo(boolean) 方法。

启动失败

如果您的应用程序启动失败,注册的 FailureAnalyzer bean 将有机会提供专用的错误消息和具体的修复问题的操作。 例如,如果您在端口 8080 上启动一个 Web 应用程序,而该端口已被占用,您应该会看到类似于以下的消息:

***************************
APPLICATION FAILED TO START
***************************

描述:

嵌入式 servlet 容器启动失败。端口 8080 已被占用。

操作:

确定并停止监听端口 8080 的进程,或者配置此应用程序监听另一个端口。
Spring Boot 提供了许多 FailureAnalyzer 实现,您也可以 添加自己的实现

如果没有故障分析器能够处理异常,您仍然可以显示完整的条件报告,以更好地了解问题所在。 为此,您需要 启用 debug 属性 或为 ConditionEvaluationReportLoggingListener 启用 DEBUG 日志

例如,如果您使用 java -jar 运行应用程序,您可以按以下方式启用 debug 属性:

$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug

延迟初始化

SpringApplication 允许应用程序进行延迟初始化。 启用延迟初始化后,bean 将在需要时创建,而不是在应用程序启动期间创建。 因此,启用延迟初始化可以减少应用程序启动所需的时间。 在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 bean 在接收到 HTTP 请求之前不会被初始化。

延迟初始化的缺点是可能会延迟发现应用程序的问题。 如果一个配置错误的 bean 被延迟初始化,启动期间将不再发生故障,问题只有在 bean 初始化时才会显现。 还必须注意确保 JVM 有足够的内存来容纳应用程序的所有 bean,而不仅仅是启动期间初始化的那些。 由于这些原因,默认情况下不会启用延迟初始化,建议在启用延迟初始化之前对 JVM 的堆大小进行微调。

可以通过在 SpringApplicationBuilder 上使用 lazyInitialization 方法或在 SpringApplication 上使用 setLazyInitialization 方法以编程方式启用延迟初始化。 或者,可以使用 spring.main.lazy-initialization 属性启用,如下例所示:

  • Properties

  • YAML

spring.main.lazy-initialization=true
spring:
  main:
    lazy-initialization: true
如果您希望对某些 bean 禁用延迟初始化,同时对应用程序的其余部分使用延迟初始化,可以使用 @Lazy(false) 注解明确将它们的延迟属性设置为 false。

自定义 Banner

启动时打印的 banner 可以通过在类路径中添加 banner.txt 文件或通过将 spring.banner.location 属性设置为该文件的位置来更改。 如果文件使用非 UTF-8 编码,您可以设置 spring.banner.charset

在您的 banner.txt 文件中,您可以使用 Environment 中可用的任何键,以及以下占位符:

Table 1. Banner 变量
变量 描述

${application.version}

应用程序的版本号,如 MANIFEST.MF 中声明的。 例如,Implementation-Version: 1.0 将打印为 1.0

${application.formatted-version}

应用程序的版本号,如 MANIFEST.MF 中声明的,并格式化为显示(用括号括起来并以 v 为前缀)。 例如 (v1.0)

${spring-boot.version}

您使用的 Spring Boot 版本。 例如 {version spring-boot}

${spring-boot.formatted-version}

您使用的 Spring Boot 版本,格式化为显示(用括号括起来并以 v 为前缀)。 例如 (v{version spring-boot})

${Ansi.NAME} (或 ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME})

其中 NAME 是 ANSI 转义码的名称。 详情请参见 AnsiPropertySource

${application.title}

应用程序的标题,如 MANIFEST.MF 中声明的。 例如 Implementation-Title: MyApp 将打印为 MyApp

如果您想以编程方式生成 banner,可以使用 SpringApplication.setBanner(…​) 方法。 使用 Banner 接口并实现您自己的 printBanner() 方法。

您还可以使用 spring.main.banner-mode 属性来确定 banner 是打印到 System.out (console),发送到配置的日志记录器 (log),还是完全不生成 (off)。

打印的 banner 将注册为以下名称的单例 bean:springBootBanner

application.titleapplication.versionapplication.formatted-version 属性仅在使用 java -jar 或 Spring Boot 启动器的 java -cp 运行时可用。 如果您运行未打包的 jar 并使用 java -cp <classpath> <mainclass> 启动,或者将应用程序作为原生镜像运行,这些值将不会被解析。

要使用 application. 属性,请使用 java -jar 作为打包的 jar 启动应用程序,或使用 java org.springframework.boot.loader.launch.JarLauncher 作为未打包的 jar 启动。 这将在构建类路径并启动应用程序之前初始化 application. banner 属性。

自定义 SpringApplication

如果 SpringApplication 的默认设置不符合您的需求,您可以创建一个本地实例并进行自定义。 例如,要关闭 banner,您可以编写:

  • Java

  • Kotlin

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		SpringApplication application = new SpringApplication(MyApplication.class);
		application.setBannerMode(Banner.Mode.OFF);
		application.run(args);
	}

}
import org.springframework.boot.Banner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class MyApplication

fun main(args: Array<String>) {
	runApplication<MyApplication>(*args) {
		setBannerMode(Banner.Mode.OFF)
	}
}
传递给 SpringApplication 构造函数的参数是 Spring bean 的配置源。 在大多数情况下,这些是对 @Configuration 类的引用,但也可以是直接引用 @Component 类。

也可以通过 application.properties 文件配置 SpringApplication。 详情请参见 外部化配置

有关配置选项的完整列表,请参见 SpringApplication API 文档。

流式构建器 API

如果您需要构建 ApplicationContext 层次结构(具有父子关系的多个上下文)或更喜欢使用流式构建器 API,您可以使用 SpringApplicationBuilder

SpringApplicationBuilder 允许您链式调用多个方法,包括允许您创建层次结构的 parentchild 方法,如下例所示:

  • Java

  • Kotlin

		new SpringApplicationBuilder().sources(Parent.class)
			.child(Application.class)
			.bannerMode(Banner.Mode.OFF)
			.run(args);
		SpringApplicationBuilder()
			.sources(Parent::class.java)
			.child(Application::class.java)
			.bannerMode(Banner.Mode.OFF)
			.run(*args)
创建 ApplicationContext 层次结构时存在一些限制。 例如,Web 组件 必须 包含在子上下文中,父子上下文使用相同的 Environment。 详情请参见 SpringApplicationBuilder API 文档。

应用程序可用性

在平台上部署时,应用程序可以使用诸如 Kubernetes Probes 的基础设施向平台提供其可用性信息。 Spring Boot 提供对常用 “liveness” 和 “readiness” 可用性状态的开箱即用支持。 如果您使用 Spring Boot 的 “actuator” 支持,这些状态将作为健康端点组暴露。

此外,您还可以通过将 ApplicationAvailability 接口注入您自己的 bean 来获取可用性状态。

存活状态

应用程序的 “Liveness” 状态表示其内部状态是否允许其正常工作,或者在当前失败时是否能够自行恢复。 损坏的 “Liveness” 状态意味着应用程序处于无法恢复的状态,基础设施应重启应用程序。

通常,"Liveness" 状态不应基于外部检查,例如 健康检查。 如果这样做,失败的外部系统(数据库、Web API、外部缓存)将触发平台上的大规模重启和级联故障。

Spring Boot 应用程序的内部状态主要由 Spring ApplicationContext 表示。 如果应用程序上下文成功启动,Spring Boot 假定应用程序处于有效状态。 一旦上下文被刷新,应用程序即被视为存活,参见 Spring Boot 应用程序生命周期及相关应用程序事件

就绪状态

应用程序的 “Readiness” 状态表示应用程序是否准备好处理流量。 失败的 “Readiness” 状态告诉平台暂时不应将流量路由到应用程序。 这通常在启动期间发生,当 CommandLineRunnerApplicationRunner 组件正在处理时,或者在应用程序认为其过于繁忙无法处理额外流量时。

一旦应用程序和命令行运行器被调用,应用程序即被视为就绪,参见 Spring Boot 应用程序生命周期及相关应用程序事件

预期在启动期间运行的任务应由 CommandLineRunnerApplicationRunner 组件执行,而不是使用 Spring 组件生命周期回调,如 @PostConstruct

管理应用程序可用性状态

应用程序组件可以随时通过注入 ApplicationAvailability 接口并调用其方法来检索当前可用性状态。 更多时候,应用程序希望监听状态更新或更新应用程序的状态。

例如,我们可以将应用程序的 "Readiness" 状态导出到文件,以便 Kubernetes "exec Probe" 可以查看该文件:

  • Java

  • Kotlin

import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MyReadinessStateExporter {

	@EventListener
	public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
		switch (event.getState()) {
			case ACCEPTING_TRAFFIC -> {
				// create file /tmp/healthy
			}
			case REFUSING_TRAFFIC -> {
				// remove file /tmp/healthy
			}
		}
	}

}
import org.springframework.boot.availability.AvailabilityChangeEvent
import org.springframework.boot.availability.ReadinessState
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component

@Component
class MyReadinessStateExporter {

	@EventListener
	fun onStateChange(event: AvailabilityChangeEvent<ReadinessState?>) {
		when (event.state) {
			ReadinessState.ACCEPTING_TRAFFIC -> {
				// create file /tmp/healthy
			}
			ReadinessState.REFUSING_TRAFFIC -> {
				// remove file /tmp/healthy
			}
			else -> {
				// ...
			}
		}
	}

}

我们还可以在应用程序发生故障且无法恢复时更新其状态:

  • Java

  • Kotlin

import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class MyLocalCacheVerifier {

	private final ApplicationEventPublisher eventPublisher;

	public MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
		this.eventPublisher = eventPublisher;
	}

	public void checkLocalCache() {
		try {
			// ...
		}
		catch (CacheCompletelyBrokenException ex) {
			AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
		}
	}

}
import org.springframework.boot.availability.AvailabilityChangeEvent
import org.springframework.boot.availability.LivenessState
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Component

@Component
class MyLocalCacheVerifier(private val eventPublisher: ApplicationEventPublisher) {

	fun checkLocalCache() {
		try {
			// ...
		} catch (ex: CacheCompletelyBrokenException) {
			AvailabilityChangeEvent.publish(eventPublisher, ex, LivenessState.BROKEN)
		}
	}

}

应用程序事件和监听器

除了常见的 Spring Framework 事件(如 ContextRefreshedEvent),SpringApplication 还会发送一些额外的应用程序事件。

某些事件实际上在 ApplicationContext 创建之前触发,因此您无法将这些事件的监听器注册为 @Bean。 您可以通过 SpringApplication.addListeners(…​) 方法或 SpringApplicationBuilder.listeners(…​) 方法注册它们。

如果您希望这些监听器无论应用程序如何创建都能自动注册,您可以在项目中添加 META-INF/spring.factories 文件,并使用 ApplicationListener 键引用您的监听器,如下例所示:

org.springframework.context.ApplicationListener=com.example.project.MyListener

应用程序事件按以下顺序发送,随着应用程序运行:

  1. ApplicationStartingEvent 在运行开始时发送,但在任何处理之前,仅限于监听器和初始化器的注册。

  2. ApplicationEnvironmentPreparedEvent 在已知将用于上下文的 Environment 但尚未创建上下文时发送。

  3. ApplicationContextInitializedEventApplicationContext 准备好且 ApplicationContextInitializers 已调用但尚未加载任何 bean 定义时发送。

  4. ApplicationPreparedEvent 在刷新开始前但 bean 定义已加载后发送。

  5. ApplicationStartedEvent 在上下文刷新后但在调用任何应用程序和命令行运行器之前发送。

  6. AvailabilityChangeEvent 在紧接着以 LivenessState.CORRECT 发送,表示应用程序被视为存活。

  7. ApplicationReadyEvent 在调用任何 应用程序和命令行运行器 后发送。

  8. AvailabilityChangeEvent 在紧接着以 ReadinessState.ACCEPTING_TRAFFIC 发送,表示应用程序已准备好处理请求。

  9. ApplicationFailedEvent 如果启动时发生异常则发送。

上述列表仅包括与 SpringApplication 相关的 SpringApplicationEvent。 除此之外,以下事件也在 ApplicationPreparedEvent 之后和 ApplicationStartedEvent 之前发布:

您通常不需要使用应用程序事件,但了解它们的存在会很有帮助。 在内部,Spring Boot 使用事件来处理各种任务。
事件监听器不应运行可能耗时较长的任务,因为它们默认在同一线程中执行。 请考虑使用 应用程序和命令行运行器

应用程序事件通过 Spring Framework 的事件发布机制发送。 该机制的一部分确保发布到子上下文监听器的事件也会发布到任何祖先上下文的监听器。 因此,如果您的应用程序使用 SpringApplication 实例的层次结构,监听器可能会收到同一类型应用程序事件的多个实例。

为了让您的监听器区分其上下文的事件和后代上下文的事件,应请求注入其应用程序上下文,然后比较注入的上下文与事件上下文。 可以通过实现 ApplicationContextAware 或如果监听器是 bean,则使用 @Autowired 注入上下文。

Web 环境

SpringApplication 会尝试为您创建正确类型的 ApplicationContext。 用于确定 WebApplicationType 的算法如下:

这意味着如果您在同一应用程序中同时使用 Spring MVC 和 Spring WebFlux 的新 WebClient,默认将使用 Spring MVC。 您可以通过调用 setWebApplicationType(WebApplicationType) 轻松覆盖此行为。

也可以通过调用 setApplicationContextFactory(…​) 完全控制使用的 ApplicationContext 类型。

在 JUnit 测试中使用 SpringApplication 时,通常希望调用 setWebApplicationType(WebApplicationType.NONE)

访问应用程序参数

如果您需要访问传递给 SpringApplication.run(…​) 的应用程序参数,可以注入 ApplicationArguments bean。 ApplicationArguments 接口提供对原始 String[] 参数以及解析的 optionnon-option 参数的访问,如下例所示:

  • Java

  • Kotlin

import java.util.List;

import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

	public MyBean(ApplicationArguments args) {
		boolean debug = args.containsOption("debug");
		List<String> files = args.getNonOptionArgs();
		if (debug) {
			System.out.println(files);
		}
		// if run with "--debug logfile.txt" prints ["logfile.txt"]
	}

}
import org.springframework.boot.ApplicationArguments
import org.springframework.stereotype.Component

@Component
class MyBean(args: ApplicationArguments) {

	init {
		val debug = args.containsOption("debug")
		val files = args.nonOptionArgs
		if (debug) {
			println(files)
		}
		// if run with "--debug logfile.txt" prints ["logfile.txt"]
	}

}
Spring Boot 还在 Spring Environment 中注册了 CommandLinePropertySource。 这允许您使用 @Value 注解注入单个应用程序参数。

使用 ApplicationRunner 或 CommandLineRunner

如果您需要在 SpringApplication 启动后运行一些特定代码,可以实现 ApplicationRunnerCommandLineRunner 接口。 这两个接口以相同的方式工作,提供单一的 run 方法,在 SpringApplication.run(…​) 完成之前调用。

此契约非常适合在应用程序启动后但开始接受流量之前运行的任务。

CommandLineRunner 接口提供对应用程序参数的访问,作为字符串数组,而 ApplicationRunner 使用前面讨论的 ApplicationArguments 接口。 以下示例显示了一个带有 run 方法的 CommandLineRunner

  • Java

  • Kotlin

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyCommandLineRunner implements CommandLineRunner {

	@Override
	public void run(String... args) {
		// Do something...
	}

}
import org.springframework.boot.CommandLineRunner
import org.springframework.stereotype.Component

@Component
class MyCommandLineRunner : CommandLineRunner {

	override fun run(vararg args: String) {
		// Do something...
	}

}

如果定义了多个必须按特定顺序调用的 CommandLineRunnerApplicationRunner bean,您可以额外实现 Ordered 接口或使用 Order 注解。

应用程序退出

每个 SpringApplication 都会向 JVM 注册一个关闭钩子,以确保 ApplicationContext 在退出时优雅关闭。 可以使用所有标准的 Spring 生命周期回调(例如 DisposableBean 接口或 @PreDestroy 注解)。

此外,如果 bean 希望在调用 SpringApplication.exit() 时返回特定退出码,可以实现 ExitCodeGenerator 接口。 此退出码随后可以传递给 System.exit() 作为状态码返回,如下例所示:

  • Java

  • Kotlin

import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class MyApplication {

	@Bean
	public ExitCodeGenerator exitCodeGenerator() {
		return () -> 42;
	}

	public static void main(String[] args) {
		System.exit(SpringApplication.exit(SpringApplication.run(MyApplication.class, args)));
	}

}
import org.springframework.boot.ExitCodeGenerator
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean

import kotlin.system.exitProcess

@SpringBootApplication
class MyApplication {

	@Bean
	fun exitCodeGenerator() = ExitCodeGenerator { 42 }

}

fun main(args: Array<String>) {
	exitProcess(SpringApplication.exit(
		runApplication<MyApplication>(*args)))
}

此外,异常也可以实现 ExitCodeGenerator 接口。 当遇到此类异常时,Spring Boot 将返回实现的 getExitCode() 方法提供的退出码。

如果存在多个 ExitCodeGenerator,将使用生成的第一个非零退出码。 要控制生成器的调用顺序,额外实现 Ordered 接口或使用 Order 注解。

管理功能

通过指定 spring.application.admin.enabled 属性,可以为应用程序启用与管理相关的功能。 这会在平台 MBeanServer 上暴露 SpringApplicationAdminMXBean。 您可以使用此功能远程管理您的 Spring Boot 应用程序。 此功能对于任何服务包装器实现也可能有用。

如果您想知道应用程序运行的 HTTP 端口,请获取键为 local.server.port 的属性。

应用程序启动跟踪

在应用程序启动期间,SpringApplicationApplicationContext 执行许多与应用程序生命周期、bean 生命周期或甚至处理应用程序事件相关的任务。

通过 ApplicationStartup,Spring Framework 允许您使用 StartupStep 对象跟踪应用程序启动序列。 这些数据可以用于性能分析,或者只是为了更好地理解应用程序启动过程。

您可以在设置 SpringApplication 实例时选择一个 ApplicationStartup 实现。 例如,要使用 BufferingApplicationStartup,您可以编写:

  • Java

  • Kotlin

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		SpringApplication application = new SpringApplication(MyApplication.class);
		application.setApplicationStartup(new BufferingApplicationStartup(2048));
		application.run(args);
	}

}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup
import org.springframework.boot.runApplication

@SpringBootApplication
class MyApplication

fun main(args: Array<String>) {
	runApplication<MyApplication>(*args) {
		applicationStartup = BufferingApplicationStartup(2048)
	}
}

Spring Framework 提供的第一个可用实现是 FlightRecorderApplicationStartup。 它将特定于 Spring 的启动事件添加到 Java Flight Recorder 会话中,旨在分析应用程序并将其 Spring 上下文生命周期与 JVM 事件(如分配、垃圾回收、类加载等)相关联。 配置后,您可以通过启用 Flight Recorder 运行应用程序来记录数据:

$ java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar demo.jar

Spring Boot 附带了 BufferingApplicationStartup 变体;此实现旨在缓冲启动步骤并将其导出到外部指标系统。 应用程序可以在任何组件中请求类型为 BufferingApplicationStartup 的 bean。

Spring Boot 还可以配置为暴露 startup 端点,以 JSON 文档形式提供此信息。

虚拟线程

如果您在 Java 21 或更高版本上运行,可以通过将 spring.threads.virtual.enabled 属性设置为 true 来启用虚拟线程。

在为您的应用程序启用此选项之前,您应考虑 阅读官方 Java 虚拟线程文档。 在某些情况下,由于“固定虚拟线程”,应用程序可能会出现较低的吞吐量;此页面还解释了如何使用 JDK Flight Recorder 或 jcmd CLI 检测此类情况。

如果启用了虚拟线程,配置线程池的属性将不再生效。 这是因为虚拟线程在 JVM 范围的平台线程池上调度,而不是在专用线程池上。
虚拟线程的一个副作用是它们是守护线程。 如果所有线程都是守护线程,JVM 将退出。 此行为在使用 @Scheduled bean 时可能会出现问题,例如,依靠它们来保持应用程序存活。 如果您使用虚拟线程,调度器线程是虚拟线程,因此是守护线程,不会保持 JVM 存活。 这不仅影响调度,其他技术也可能出现这种情况。 为了在所有情况下保持 JVM 运行,建议将 spring.main.keep-alive 属性设置为 true。 这确保即使所有线程都是虚拟线程,JVM 仍会保持存活。