SpringApplication

SpringApplication (Javadoc) クラスは、main() メソッドから起動される Spring アプリケーションをブートストラップする便利な方法を提供します。多くの場合、次の例に示すように、静的 SpringApplication.run(Class, String…​) (Javadoc) メソッドに委譲できます。

  • 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.1)

2024-12-19T12:20:12.332Z  INFO 126957 --- [           main] o.s.b.d.f.logexample.MyApplication       : Starting MyApplication using Java 17.0.13 with PID 126957 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2024-12-19T12:20:12.338Z  INFO 126957 --- [           main] o.s.b.d.f.logexample.MyApplication       : No active profile set, falling back to 1 default profile: "default"
2024-12-19T12:20:15.485Z  INFO 126957 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2024-12-19T12:20:15.549Z  INFO 126957 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-12-19T12:20:15.552Z  INFO 126957 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.34]
2024-12-19T12:20:15.725Z  INFO 126957 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-12-19T12:20:15.734Z  INFO 126957 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3258 ms
2024-12-19T12:20:17.301Z  INFO 126957 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2024-12-19T12:20:17.340Z  INFO 126957 --- [           main] o.s.b.d.f.logexample.MyApplication       : Started MyApplication in 6.042 seconds (process running for 6.85)
2024-12-19T12:20:17.366Z  INFO 126957 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
2024-12-19T12:20:17.387Z  INFO 126957 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete

デフォルトでは、INFO ロギングメッセージが表示されます。これには、アプリケーションを起動したユーザーなど、関連するスタートアップの詳細が含まれます。INFO 以外のログレベルが必要な場合は、ログレベルの説明に従って設定できます。アプリケーションバージョンは、メインアプリケーションクラスのパッケージの実装バージョンを使用して決定されます。spring.main.log-startup-info を false に設定することにより、始動情報のロギングをオフにできます。これにより、アプリケーションのアクティブなプロファイルのログもオフになります。

起動時に追加のログ記録を追加するには、SpringApplication (Javadoc) のサブクラスで logStartupInfo(boolean) をオーバーライドできます。

起動失敗

アプリケーションの起動に失敗した場合、登録された FailureAnalyzer (Javadoc) 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 (Javadoc) 実装を提供しており、独自の実装を追加することもできます。

例外を処理できる障害アナライザーがない場合でも、完全な状態レポートを表示して、何が問題だったのかをよりよく理解することができます。そのためには、debug プロパティを有効にするか、ConditionEvaluationReportLoggingListener (Javadoc) DEBUG ログを有効にする必要があります。

たとえば、java -jar を使用してアプリケーションを実行している場合、次のように debug プロパティを有効にできます。

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

遅延初期化

SpringApplication (Javadoc) を使用すると、アプリケーションを遅延初期化できます。遅延初期化を有効にすると、アプリケーションの起動時ではなく、必要に応じて Bean が作成されます。その結果、遅延初期化を有効にすると、アプリケーションの起動にかかる時間が短縮されます。Web アプリケーションでは、遅延初期化を有効にすると、多くの Web 関連 Bean が HTTP リクエストを受信するまで初期化されません。

遅延初期化の欠点は、アプリケーションの問題の発見を遅らせる可能性があることです。誤って構成された Bean が遅延初期化された場合、起動時に障害は発生せず、Bean が初期化されたときにのみ問題が明らかになります。また、JVM に、起動時に初期化される Bean だけでなく、アプリケーションのすべての Bean を収容するのに十分なメモリがあることを確認する必要があります。これらの理由により、遅延初期化はデフォルトでは有効になっていないため、遅延初期化を有効にする前に JVM のヒープサイズの微調整を行うことをお勧めします。

遅延初期化は、SpringApplicationBuilder (Javadoc) の lazyInitialization メソッドまたは SpringApplication (Javadoc) の setLazyInitialization メソッドを使用してプログラムで有効にできます。または、次の例に示すように、spring.main.lazy-initialization プロパティを使用して有効にすることもできます。

  • プロパティ

  • YAML

spring.main.lazy-initialization=true
spring:
  main:
    lazy-initialization: true
残りのアプリケーションで遅延初期化を使用しているときに特定の Bean の遅延初期化を無効にする場合は、@Lazy(false) アノテーションを使用して遅延属性を明示的に false に設定できます。

バナーのカスタマイズ

起動時に出力されるバナーは、クラスパスに banner.txt ファイルを追加するか、spring.banner.location プロパティをそのようなファイルの場所に設定することで変更できます。ファイルに UTF-8 以外のエンコーディングがある場合は、spring.banner.charset を設定できます。

banner.txt ファイル内では、Environment (Javadoc) で使用可能な任意のキーと、次のプレースホルダーのいずれかを使用できます。

表 1: バナー変数
変数 説明

${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.1.

${spring-boot.formatted-version}

使用する Spring Boot バージョン。表示用にフォーマットされています(括弧で囲まれ、接頭部が v)。たとえば、(v3.4.1)

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

Where NAME is the name of an ANSI escape code. See AnsiPropertySource (Javadoc) for details.

${application.title}

MANIFEST.MF で宣言されているアプリケーションのタイトル。たとえば、Implementation-Title: MyApp は MyApp として出力されます。

プログラムでバナーを生成する場合は、SpringApplication.setBanner(…​) メソッドを使用できます。Banner (Javadoc) インターフェースを使用して、独自の printBanner() メソッドを実装します。

また、spring.main.banner-mode プロパティを使用して、バナーを System.out (標準 Javadoc) に出力するか (console)、構成されたロガーに送信するか (log)、まったく生成しないか (off) を決定することもできます。

出力されたバナーは、springBootBanner という名前でシングルトン Bean として登録されます。

application.titleapplication.versionapplication.formatted-version プロパティは、Spring Boot ランチャーで java -jar または java -cp を使用している場合にのみ使用できます。解凍された jar を実行していて java -cp <classpath> <mainclass> で起動している場合、またはアプリケーションをネイティブイメージとして実行している場合、値は解決されません。

application. プロパティを使用するには、アプリケーションを java -jar を使用してパックされた jar として起動するか、java org.springframework.boot.loader.launch.JarLauncher を使用してアンパックされた jar として起動します。これにより、クラスパスを構築してアプリを起動する前に、application. バナープロパティが初期化されます。

SpringApplication のカスタマイズ

SpringApplication (Javadoc) のデフォルト設定が気に入らない場合は、代わりにローカルインスタンスを作成してカスタマイズできます。例: バナーをオフにするには、次のように記述します。

  • 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 (Javadoc) に渡されるコンストラクター引数は、Spring Bean の構成ソースです。ほとんどの場合、これらは @Configuration (Javadoc) クラスへの参照ですが、@Component (Javadoc) クラスへの直接参照である場合もあります。

application.properties ファイルを使用して SpringApplication (Javadoc) を構成することもできます。詳細については、環境別の設定切り替えを参照してください。

構成オプションの完全なリストについては、SpringApplication (Javadoc) API ドキュメントを参照してください。

Fluent Builder API

ApplicationContext (Javadoc) 階層 (親子関連を持つ複数のコンテキスト) を構築する必要がある場合、または Fluent Builder API を使用する場合は、SpringApplicationBuilder (Javadoc) を使用できます。

SpringApplicationBuilder (Javadoc) を使用すると、複数のメソッド呼び出しをまとめて チェーンすることができ、次の例に示すように、階層を作成できる parent メソッドと child メソッドが含まれています。

  • 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 (Javadoc) 階層を作成する際には、いくつかの制限があります。例: Web コンポーネントは子コンテキスト内に含まれている必要があり、親コンテキストと子コンテキストの両方に同じ Environment (Javadoc) が使用されます。詳細については、SpringApplicationBuilder (Javadoc) API ドキュメントを参照してください。

アプリケーションの可用性

アプリケーションをプラットフォームにデプロイすると、Kubernetes プローブ (英語) などのインフラストラクチャを使用して、アプリケーションがその可用性に関する情報をプラットフォームに提供できます。Spring Boot には、一般的に使用される「活性」と「準備」の可用性状態のサポートが含まれています。Spring Boot の「アクチュエーター」サポートを使用している場合、これらの状態はヘルスエンドポイントグループとして公開されます。

さらに、ApplicationAvailability (Javadoc) インターフェースを独自の Bean に挿入することで、可用性の状態を取得することもできます。

活性状態

アプリケーションの「活性」状態は、その内部状態によってアプリケーションが正しく機能するかどうか、現在障害が発生している場合は自動的に回復するかどうかを示します。壊れた「活性」状態は、アプリケーションが回復できない状態にあり、インフラストラクチャがアプリケーションを再起動する必要があることを意味します。

一般に、"Liveness" 状態はヘルスチェックなどの外部チェックに基づいてはなりません。そうした場合、障害が発生した外部システム (データベース、Web API、外部キャッシュ) によって、大規模な再起動がトリガーされ、プラットフォーム全体で障害が連鎖的に発生します。

Spring Boot アプリケーションの内部状態は、主に Spring ApplicationContext (Javadoc) によって表されます。アプリケーションコンテキストが正常に開始された場合、Spring Boot はアプリケーションが有効な状態にあると想定します。コンテキストがリフレッシュされるとすぐに、アプリケーションはライブであるとみなされます。Spring Boot アプリケーションのライフサイクルと関連するアプリケーションイベントを参照してください。

準備状態

アプリケーションの「準備」状態は、アプリケーションがトラフィックを処理する準備ができているかどうかを示します。「準備」状態が失敗している場合、プラットフォームは現時点ではトラフィックをアプリケーションにルーティングすべきではないと認識します。これは通常、起動時、CommandLineRunner (Javadoc) および ApplicationRunner (Javadoc) コンポーネントの処理中、またはアプリケーションが追加のトラフィックに対してビジー状態であると判断した場合に発生します。

アプリケーションとコマンドラインランナーが呼び出されるとすぐに、アプリケーションは準備ができていると見なされます。Spring Boot アプリケーションのライフサイクルと関連するアプリケーションイベントを参照してください。

起動時に実行されることが予想されるタスクは、@PostConstruct (英語) などの Spring コンポーネントライフサイクルコールバックを使用するのではなく、CommandLineRunner (Javadoc) および ApplicationRunner (Javadoc) コンポーネントによって実行される必要があります。

アプリケーションの可用性状態の管理

アプリケーションコンポーネントは、ApplicationAvailability (Javadoc) インターフェースを挿入し、そのメソッドを呼び出すことで、いつでも現在の可用性状態を取得できます。多くの場合、アプリケーションは状態の更新をリッスンしたり、アプリケーションの状態を更新したりする必要があります。

例: アプリケーションの「準備」状態をファイルにエクスポートして、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)
		}
	}

}

アプリケーションイベントとリスナー

ContextRefreshedEvent (Javadoc) などの通常の Spring Framework イベントに加えて、SpringApplication (Javadoc) はいくつかの追加のアプリケーションイベントを送信します。

一部のイベントは実際には ApplicationContext (Javadoc) が作成される前にトリガーされるため、それらのイベントにリスナーを @Bean (Javadoc) として登録することはできません。それらは、SpringApplication.addListeners(…​) メソッドまたは SpringApplicationBuilder.listeners(…​) メソッドを使用して登録できます。

アプリケーションの作成方法に関係なく、これらのリスナーを自動的に登録したい場合は、次の例に示すように、プロジェクトに META-INF/spring.factories ファイルを追加し、ApplicationListener (Javadoc) キーを使用してリスナーを参照できます。

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

アプリケーションが実行されると、アプリケーションイベントは次の順序で送信されます。

  1. ApplicationStartingEvent (Javadoc) は、リスナーと初期化子の登録を除き、実行の開始時に、あらゆる処理の前に送信されます。

  2. コンテキスト内で使用される Environment (Javadoc) がわかっているが、コンテキストが作成される前に、ApplicationEnvironmentPreparedEvent (Javadoc) が送信されます。

  3. ApplicationContext (Javadoc) が準備され、ApplicationContextInitializers が呼び出されましたが、Bean 定義がロードされる前に、ApplicationContextInitializedEvent (Javadoc) が送信されます。

  4. ApplicationPreparedEvent (Javadoc) は、リフレッシュが開始される直前、ただし Bean 定義がロードされた後に送信されます。

  5. ApplicationStartedEvent (Javadoc) は、コンテキストがリフレッシュされた後、アプリケーションおよびコマンドラインランナーが呼び出される前に送信されます。

  6. アプリケーションがライブであるとみなされることを示すために、AvailabilityChangeEvent (Javadoc) LivenessState.CORRECT (Javadoc) の直後に送信されます。

  7. アプリケーションおよびコマンドラインランナーが呼び出された後、ApplicationReadyEvent (Javadoc) が送信されます。

  8. AvailabilityChangeEvent (Javadoc) ReadinessState.ACCEPTING_TRAFFIC (Javadoc) の直後に送信され、アプリケーションがリクエストを処理する準備ができていることを示します。

  9. 起動時に例外が発生した場合、ApplicationFailedEvent (Javadoc) が送信されます。

上記のリストには、SpringApplication (Javadoc) に関連付けられている SpringApplicationEvent のみが含まれています。これらに加えて、ApplicationPreparedEvent (Javadoc) の後、ApplicationStartedEvent (Javadoc) の前に次のイベントも公開されます。

多くの場合、アプリケーションイベントを使用する必要はありませんが、それらが存在することを知っておくと便利です。内部的に、Spring Boot はイベントを使用してさまざまなタスクを処理します。
イベントリスナーは、デフォルトでは同じスレッドで実行されるため、長時間かかる可能性のあるタスクを実行しないでください。代わりに、アプリケーションランナーとコマンドラインランナーの使用を検討してください。

アプリケーションイベントは、Spring Framework のイベント公開メカニズムを使用して送信されます。このメカニズムの一部は、子コンテキストのリスナーに公開されたイベントが、祖先コンテキストのリスナーにも公開されることを保証します。この結果、アプリケーションが SpringApplication (Javadoc) インスタンスの階層を使用する場合、リスナーは同じタイプのアプリケーションイベントの複数のインスタンスを受信する可能性があります。

リスナーが自身のコンテキストのイベントと子孫コンテキストのイベントを区別できるようにするには、アプリケーションコンテキストの挿入をリクエストし、挿入されたコンテキストをイベントのコンテキストと比較する必要があります。コンテキストは、ApplicationContextAware (Javadoc) を実装するか、リスナーが Bean の場合は @Autowired (Javadoc) を使用して挿入できます。

Web 環境

SpringApplication (Javadoc) は、ユーザーに代わって適切な型の ApplicationContext (Javadoc) を作成しようとします。WebApplicationType (Javadoc) を決定するために使用されるアルゴリズムは次のとおりです。

つまり、同じアプリケーションで Spring MVC と Spring WebFlux の新しい WebClient (Javadoc) を使用している場合、デフォルトでは Spring MVC が使用されることになります。setWebApplicationType(WebApplicationType) を呼び出すことで、これを簡単にオーバーライドできます。

setApplicationContextFactory(…​) を呼び出すことによって使用される ApplicationContext (Javadoc) 型を完全に制御することも可能です。

JUnit テスト内で SpringApplication (Javadoc) を使用する場合は、setWebApplicationType(WebApplicationType.NONE) を呼び出すことが望ましい場合がよくあります。

アプリケーション引数へのアクセス

SpringApplication.run(…​) に渡されたアプリケーション引数にアクセスする必要がある場合は、ApplicationArguments (Javadoc) Bean を挿入できます。次の例に示すように、ApplicationArguments (Javadoc) インターフェースは、生の String[] 引数と解析された option および non-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 (Javadoc) とともに CommandLinePropertySource (Javadoc) も登録します。これにより、@Value (Javadoc) アノテーションを使用して単一のアプリケーション引数を挿入することもできます。

ApplicationRunner または CommandLineRunner の使用

SpringApplication (Javadoc) が起動した後に特定のコードを実行する必要がある場合は、ApplicationRunner (Javadoc) または CommandLineRunner (Javadoc) インターフェースを実装できます。両方のインターフェースは同じように動作し、SpringApplication.run(…​) が完了する直前に呼び出される単一の run メソッドを提供します。

この契約は、アプリケーションの起動後、トラフィックの受け入れを開始する前に実行する必要があるタスクに適しています。

CommandLineRunner (Javadoc) インターフェースは、文字列配列としてアプリケーション引数へのアクセスを提供しますが、ApplicationRunner (Javadoc) は前述の ApplicationArguments (Javadoc) インターフェースを使用します。次の例は、run メソッドを使用した CommandLineRunner (Javadoc) を示しています。

  • 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...
	}

}

特定の順序で呼び出す必要がある複数の CommandLineRunner (Javadoc) または ApplicationRunner (Javadoc) Bean が定義されている場合は、追加で Ordered (Javadoc) インターフェースを実装するか、Order (Javadoc) アノテーションを使用することができます。

アプリケーション終了

SpringApplication (Javadoc) は、終了時に ApplicationContext (Javadoc) が正常に終了するように、JVM にシャットダウンフックを登録します。すべての標準 Spring ライフサイクルコールバック (DisposableBean (Javadoc) インターフェースや @PreDestroy (英語) アノテーションなど) を使用できます。

さらに、SpringApplication.exit() が呼び出されたときに特定の終了コードを返す必要がある場合、Bean は ExitCodeGenerator (Javadoc) インターフェースを実装できます。この終了コードは、次の例に示すように、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 (Javadoc) インターフェースは例外によって実装される場合もあります。このような例外が発生すると、Spring Boot は実装された getExitCode() メソッドによって提供される終了コードを返します。

ExitCodeGenerator (Javadoc) が複数ある場合は、最初に生成されたゼロ以外の終了コードが使用されます。ジェネレーターが呼び出される順序を制御するには、さらに Ordered (Javadoc) インターフェースを実装するか、Order (Javadoc) アノテーションを使用します。

管理機能

spring.application.admin.enabled プロパティを指定することで、アプリケーションの管理関連機能を有効にすることができます。これにより、プラットフォーム MBeanServer (標準 Javadoc) 上の SpringApplicationAdminMXBean (Javadoc) が公開されます。この機能を使用して、Spring Boot アプリケーションをリモートで管理できます。この機能は、サービスラッパーの実装にも役立ちます。

アプリケーションが実行されている HTTP ポートを知りたい場合は、local.server.port のキーを持つプロパティを取得します。

アプリケーションのスタートアップの追跡

アプリケーションの起動中、SpringApplication (Javadoc) ApplicationContext (Javadoc) は、アプリケーションのライフサイクル、Bean のライフサイクル、さらにはアプリケーションイベントの処理に関連する多くのタスクを実行します。ApplicationStartup (Javadoc) 、Spring Framework、StartupStep を使用してアプリケーションの起動シーケンスを追跡できますオブジェクトを使用します。このデータは、プロファイリングの目的で収集することも、アプリケーションの起動プロセスをより深く理解するために収集することもできます。

SpringApplication (Javadoc) インスタンスを設定するときに、ApplicationStartup (Javadoc) 実装を選択できます。例: BufferingApplicationStartup (Javadoc) を使用するには、次のように記述します。

  • 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)
	}
}

最初の利用可能な実装である FlightRecorderApplicationStartup (Javadoc) は、Spring Framework によって提供されます。これは、Spring 固有の起動イベントを Java Flight Recorder セッションに追加し、アプリケーションのプロファイリングと、Spring コンテキストライフサイクルと JVM イベント (割り当て、GC、クラスの読み込みなど) の相関関係の把握を目的としています。設定が完了したら、Flight Recorder を有効にしてアプリケーションを実行してデータを記録できます。

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

Spring Boot には BufferingApplicationStartup (Javadoc) バリアントが付属しています。この実装は、起動手順をバッファリングし、外部のメトリクスシステムに排出することを目的としています。アプリケーションは、任意のコンポーネントで型 BufferingApplicationStartup (Javadoc) の Bean を要求できます。

Spring Boot は、この情報を JSON ドキュメントとして提供する startup エンドポイントを公開するように構成することもできます。

仮想スレッド

Java 21 以降で実行している場合は、プロパティ spring.threads.virtual.enabled を true に設定することで仮想スレッドを有効にできます。

アプリケーションでこのオプションをオンにする前に、Java 仮想スレッドの公式ドキュメントを読む [Oracle] ことを検討してください。場合によっては、「固定された仮想スレッド」が原因でアプリケーションのスループットが低下することがあります。このページでは、JDK Flight Recorder または jcmd CLI を使用してそのようなケースを検出する方法についても説明します。

仮想スレッドが有効になっている場合、スレッドプールを構成するプロパティは効果がありません。これは、仮想スレッドが専用のスレッドプールではなく、JVM 全体のプラットフォームスレッドプールでスケジュールされるためです。
仮想スレッドの副作用の 1 つは、それがデーモンスレッドであることです。すべてのスレッドがデーモンスレッドである場合、JVM は終了します。この動作は、たとえば、アプリケーションの稼働を維持するために @Scheduled (Javadoc) Bean に依存している場合に問題となる可能性があります。仮想スレッドを使用する場合、スケジューラスレッドは仮想スレッドであるためデーモンスレッドとなり、JVM を稼働させ続けることはできません。これはスケジューリングに影響するだけでなく、他のテクノロジにも当てはまります。すべての場合に JVM を稼働させ続けるには、プロパティ spring.main.keep-alive を true に設定することをお勧めします。これにより、すべてのスレッドが仮想スレッドであっても、JVM を稼働させ続けることができます。