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.4.5)

2025-04-24T13:04:51.596Z  INFO 128164 --- [           main] o.s.b.d.f.logexample.MyApplication       : Starting MyApplication using Java 17.0.15 with PID 128164 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2025-04-24T13:04:51.610Z  INFO 128164 --- [           main] o.s.b.d.f.logexample.MyApplication       : No active profile set, falling back to 1 default profile: "default"
2025-04-24T13:04:55.746Z  INFO 128164 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2025-04-24T13:04:55.802Z  INFO 128164 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-04-24T13:04:55.811Z  INFO 128164 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.40]
2025-04-24T13:04:56.023Z  INFO 128164 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-04-24T13:04:56.032Z  INFO 128164 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 4166 ms
2025-04-24T13:04:58.277Z  INFO 128164 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-04-24T13:04:58.336Z  INFO 128164 --- [           main] o.s.b.d.f.logexample.MyApplication       : Started MyApplication in 9.643 seconds (process running for 11.397)
2025-04-24T13:04:58.369Z  INFO 128164 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
2025-04-24T13:04:58.388Z  INFO 128164 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete

預設情況下,會顯示 INFO 級別的日誌訊息,包括一些相關的啟動詳情,例如啟動應用的使用者。如果您需要除 INFO 之外的日誌級別,可以進行設定,如 日誌級別 中所述。應用版本是使用主應用類包中的實現版本確定的。透過將 spring.main.log-startup-info 設定為 false 可以關閉啟動資訊日誌記錄。這也會關閉應用活動 Profile 的日誌記錄。

要在啟動期間新增額外的日誌記錄,您可以在 SpringApplication 的子類中覆蓋 logStartupInfo(boolean) 方法。

啟動失敗

如果您的應用啟動失敗,註冊的 FailureAnalyzer Bean 有機會提供專門的錯誤訊息和解決問題的具體操作。例如,如果您在埠 8080 上啟動一個 Web 應用,而該埠已被佔用,您應該會看到類似於以下內容的訊息

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

Description:

Embedded servlet container failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that is listening on port 8080 or configure this application to listen on another port.
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) 註解將其 lazy 屬性顯式設定為 false。

定製 Banner

可以在啟動時透過將 banner.txt 檔案新增到類路徑中,或將 spring.banner.location 屬性設定為此類檔案的位置來更改列印的 banner。如果檔案的編碼不是 UTF-8,可以設定 spring.banner.charset

在您的 banner.txt 檔案中,您可以使用 Environment 中可用的任何 key 以及以下任何佔位符

表 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 版本。例如 3.4.5

${spring-boot.formatted-version}

您正在使用的 Spring Boot 版本,格式化用於顯示(用括號括起來並以 v 開頭)。例如 (v3.4.5)

${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)、傳送到配置的 logger (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 探針等基礎設施向平臺提供有關其可用性的資訊。Spring Boot 內建支援常用的“活躍度 (liveness)”和“就緒度 (readiness)”可用性狀態。如果您使用 Spring Boot 的 “actuator” 支援,這些狀態將作為健康端點組暴露。

此外,您還可以透過將 ApplicationAvailability 介面注入到您自己的 bean 中來獲取可用性狀態。

活躍度狀態

應用的“活躍度”狀態表明其內部狀態是否允許其正常工作,或者在當前失敗時是否可以自行恢復。損壞的“活躍度”狀態意味著應用處於無法恢復的狀態,基礎設施應該重啟應用。

通常,“活躍度”狀態不應基於外部檢查,例如 健康檢查。如果基於外部檢查,一個失敗的外部系統(資料庫、Web API、外部快取)將導致平臺內大規模重啟和級聯故障。

Spring Boot 應用的內部狀態主要由 Spring ApplicationContext 表示。如果應用上下文成功啟動,Spring Boot 會認為應用處於有效狀態。一旦上下文重新整理完成,應用就被認為是活躍的,請參閱 Spring Boot 應用生命週期和相關的應用事件

就緒度狀態

應用的“就緒度”狀態表明應用是否已準備好處理流量。失敗的“就緒度”狀態告訴平臺暫時不應將流量路由到該應用。這通常發生在啟動期間,當 CommandLineRunnerApplicationRunner 元件正在處理時,或者在任何時候應用認為它太忙而無法處理額外流量時。

一旦應用和命令列執行器被呼叫,應用就被認為是就緒的,請參閱 Spring Boot 應用生命週期和相關的應用事件

期望在啟動期間執行的任務應由 CommandLineRunnerApplicationRunner 元件執行,而不是使用 Spring 元件生命週期回撥(例如 @PostConstruct)。

管理應用可用性狀態

應用元件可以隨時透過注入 ApplicationAvailability 介面並呼叫其方法來獲取當前的可用性狀態。更常見的是,應用會希望監聽狀態更新或更新應用狀態。

例如,我們可以將應用的“就緒度”狀態匯出到檔案中,以便 Kubernetes 的“exec 探針”可以檢視該檔案

  • 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 Boot 透過 Actuator 健康端點為 Kubernetes 提供“活躍度”和“就緒度” HTTP 探針。您可以在 相關章節 中獲取有關在 Kubernetes 上部署 Spring Boot 應用的更多指導。

應用事件和監聽器

除了常見的 Spring Framework 事件(例如 ContextRefreshedEvent)之外,SpringApplication 還會發送一些額外的應用事件。

某些事件實際上在 ApplicationContext 建立之前觸發,因此您無法將其作為 @Bean 註冊監聽器。您可以使用 SpringApplication.addListeners(…​) 方法或 SpringApplicationBuilder.listeners(…​) 方法註冊它們。

如果您希望這些監聽器自動註冊,無論應用以何種方式建立,您都可以向您的專案新增一個 META-INF/spring.factories 檔案,並使用 ApplicationListener key 引用您的監聽器,如下例所示

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

應用事件在您的應用執行時按以下順序傳送

  1. 在執行開始時,但在註冊監聽器和初始化器之外的任何處理之前,傳送 ApplicationStartingEvent

  2. 當上下文中使用的 Environment 已知,但在上下文建立之前,傳送 ApplicationEnvironmentPreparedEvent

  3. ApplicationContext 準備好且 ApplicationContextInitializer 已被呼叫,但在載入任何 bean 定義之前,傳送 ApplicationContextInitializedEvent

  4. 在重新整理開始之前,但在 bean 定義載入之後,傳送 ApplicationPreparedEvent

  5. 在上下文重新整理之後,但在呼叫任何應用和命令列執行器之前,傳送 ApplicationStartedEvent

  6. 緊隨其後傳送一個帶有 LivenessState.CORRECTAvailabilityChangeEvent,表示應用被認為是活躍的。

  7. 在呼叫任何應用和命令列執行器之後,傳送 ApplicationReadyEvent

  8. 緊隨其後傳送一個帶有 ReadinessState.ACCEPTING_TRAFFICAvailabilityChangeEvent,表示應用已準備好處理請求。

  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 屬性,可以為應用程式啟用與管理相關的功能。這會將 SpringApplicationAdminMXBean 暴露在平臺 MBeanServer 上。您可以使用此功能遠端管理您的 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 事件(例如分配、GC、類載入等)相關聯。配置完成後,您可以執行啟用 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 虛擬執行緒文件。在某些情況下,應用程式可能會由於“固定虛擬執行緒”(Pinned Virtual Threads)而導致吞吐量降低;此頁面還解釋瞭如何使用 JDK Flight Recorder 或 jcmd CLI 檢測此類情況。

如果啟用了虛擬執行緒,配置執行緒池的屬性將不再起作用。這是因為虛擬執行緒是在 JVM 範圍的平臺執行緒池上排程的,而不是在專用執行緒池上。
虛擬執行緒的一個副作用是它們是守護執行緒。如果 JVM 的所有執行緒都是守護執行緒,則 JVM 將退出。當您依賴於 @Scheduled bean(例如,為了保持應用程式處於活動狀態)時,此行為可能會成為問題。如果您使用虛擬執行緒,排程程式執行緒是虛擬執行緒,因此是守護執行緒,並且不會保持 JVM 處於活動狀態。這不僅會影響排程,也可能發生在其他技術中。為了在所有情況下保持 JVM 執行,建議將屬性 spring.main.keep-alive 設定為 true。這確保了 JVM 保持活動狀態,即使所有執行緒都是虛擬執行緒。