Spring Boot アプリケーション

このセクションには、Spring Boot アプリケーションに直接関連するトピックが含まれています。

独自の FailureAnalyzer を作成する

FailureAnalyzer (Javadoc) は、起動時に例外をインターセプトし、それを FailureAnalysis (Javadoc) にラップされた人間が読み取れるメッセージに変換する優れた方法です。Spring Boot は、アプリケーションコンテキスト関連の例外、JSR-303 検証などのためのこのようなアナライザーを提供します。独自に作成することもできます。

AbstractFailureAnalyzer (Javadoc) は、処理する例外に指定された例外型が存在するかどうかを確認する、FailureAnalyzer (Javadoc) の便利な拡張です。これを継承して、実装が例外を実際に存在する場合にのみ例外を処理できるようにすることができます。何らかの理由で例外を処理できない場合は、null を返して、別の実装に例外を処理できるようにします。

FailureAnalyzer (Javadoc) 実装は META-INF/spring.factories に登録する必要があります。次の例では ProjectConstraintViolationFailureAnalyzer を登録します。

org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
BeanFactory (Javadoc) または Environment (Javadoc) にアクセスする必要がある場合は、FailureAnalyzer (Javadoc) 実装のコンストラクター引数として宣言します。

自動構成のトラブルシューティング

Spring Boot 自動構成は、「正しい動作をする」ために最善を尽くしますが、時には失敗することがあり、その理由を説明するのは難しい場合があります。

どの Spring Boot ApplicationContext (Javadoc) でも、非常に便利な ConditionEvaluationReport (Javadoc) が利用できます。DEBUG ログ出力を有効にすると、これを表示できます。spring-boot-actuator ( アクチュエーターセクションを参照) を使用する場合は、レポートを JSON でレンダリングする conditions エンドポイントもあります。そのエンドポイントを使用してアプリケーションをデバッグし、実行時に Spring Boot によって追加された機能 (および追加されなかった機能) を確認します。

ソースコードと API ドキュメントを確認することで、さらに多くの質問に答えることができます。コードを読むときは、次の経験則を覚えておいてください。

  • *AutoConfiguration というクラスを探して、そのソースを参照してください。@Conditional* アノテーションに特に注意して、どの機能がいつ有効になるかを調べましょう。コマンドラインに --debug を追加するか、システムプロパティ -Ddebug を追加すると、アプリで行われたすべての自動構成決定のログがコンソールに表示されます。アクチュエーターが有効になっている実行中のアプリケーションでは、同じ情報については conditions エンドポイント (/actuator/conditions または JMX の同等のもの) を参照してください。

  • @ConfigurationProperties (Javadoc) であるクラス ( ServerProperties (Javadoc) など) を探し、そこから利用可能な外部構成オプションを読み取ります。@ConfigurationProperties (Javadoc) アノテーションには、外部プロパティのプレフィックスとして機能する name 属性があります。したがって、ServerProperties (Javadoc) には prefix="server" があり、その構成プロパティは server.portserver.address などです。アクチュエーターが有効になっている実行中のアプリケーションで、configprops エンドポイントを確認します。

  • Binder (Javadoc) で bind メソッドを使用して、Environment (Javadoc) から構成値を緩やかな方法で明示的に取得します。多くの場合、プレフィックスとともに使用されます。

  • Environment (Javadoc) に直接バインドする @Value (Javadoc) アノテーションを探します。

  • 通常、Environment (Javadoc) から解決されたプレースホルダーを使用して評価される SpEL 式に応じて機能のオン / オフを切り替える @ConditionalOnExpression (Javadoc) アノテーションを探します。

開始する前に環境または ApplicationContext をカスタマイズする

SpringApplication (Javadoc) には、コンテキストまたは環境にカスタマイズを適用するために使用される ApplicationListener (Javadoc) および ApplicationContextInitializer (Javadoc) 実装があります。Spring Boot は、内部で使用するために META-INF/spring.factories からこのようなカスタマイズをいくつかロードします。追加のカスタマイズを登録する方法は複数あります。

  • プログラム的に、アプリケーションごとに、実行前に SpringApplication (Javadoc) の addListeners メソッドと addInitializers メソッドを呼び出します。

  • 宣言的に、すべてのアプリケーションについて、META-INF/spring.factories を追加し、すべてのアプリケーションがライブラリとして使用する jar ファイルをパッケージ化します。

SpringApplication (Javadoc) は、いくつかの特別な ApplicationEvents (Javadoc) をリスナーに送信し (コンテキストが作成される前もいくつかあります)、次に、ApplicationContext (Javadoc) によって発行されたイベントのリスナーも登録します。完全なリストについては、「Spring Boot の機能」セクションのアプリケーションイベントとリスナーを参照してください。

EnvironmentPostProcessor (Javadoc) を使用してアプリケーションコンテキストがリフレッシュされる前に、Environment (Javadoc) をカスタマイズすることもできます。次の例に示すように、各実装は META-INF/spring.factories に登録する必要があります。

org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor

実装では任意のファイルをロードして Environment (Javadoc) に追加できます。たとえば、次の例ではクラスパスから YAML 構成ファイルをロードします。

  • Java

  • Kotlin

import java.io.IOException;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;

public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {

	private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

	@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		Resource path = new ClassPathResource("com/example/myapp/config.yml");
		PropertySource<?> propertySource = loadYaml(path);
		environment.getPropertySources().addLast(propertySource);
	}

	private PropertySource<?> loadYaml(Resource path) {
		Assert.isTrue(path.exists(), () -> "Resource " + path + " does not exist");
		try {
			return this.loader.load("custom-resource", path).get(0);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
		}
	}

}
import org.springframework.boot.SpringApplication
import org.springframework.boot.env.EnvironmentPostProcessor
import org.springframework.boot.env.YamlPropertySourceLoader
import org.springframework.core.env.ConfigurableEnvironment
import org.springframework.core.env.PropertySource
import org.springframework.core.io.ClassPathResource
import org.springframework.core.io.Resource
import org.springframework.util.Assert
import java.io.IOException

class MyEnvironmentPostProcessor : EnvironmentPostProcessor {

	private val loader = YamlPropertySourceLoader()

	override fun postProcessEnvironment(environment: ConfigurableEnvironment, application: SpringApplication) {
		val path: Resource = ClassPathResource("com/example/myapp/config.yml")
		val propertySource = loadYaml(path)
		environment.propertySources.addLast(propertySource)
	}

	private fun loadYaml(path: Resource): PropertySource<*> {
		Assert.isTrue(path.exists()) { "Resource $path does not exist" }
		return try {
			loader.load("custom-resource", path)[0]
		} catch (ex: IOException) {
			throw IllegalStateException("Failed to load yaml configuration from $path", ex)
		}
	}

}
Environment (Javadoc) には、Spring Boot がデフォルトでロードする通常のプロパティソースがすべて用意されています。そのため、環境からファイルの場所を取得できます。前の例では、リストの最後に custom-resource プロパティソースを追加して、通常の他の場所のいずれかで定義されたキーが優先されるようにしています。カスタム実装では、別の順序を定義できます。
@SpringBootApplication (Javadoc) @PropertySource (Javadoc) を使用することは、Environment (Javadoc) にカスタムリソースをロードする便利な方法のように思われるかもしれませんが、お勧めしません。このようなプロパティソースは、アプリケーションコンテキストがリフレッシュされるまで Environment (Javadoc) に追加されません。リフレッシュが始まる前に読み取られる logging.* や spring.main.* などの特定のプロパティを構成するには遅すぎます。

ApplicationContext 階層を構築する (親またはルートコンテキストの追加)

SpringApplicationBuilder (Javadoc) クラスを使用して、親 / 子 ApplicationContext (Javadoc) 階層を作成できます。詳細については、「Spring Boot の機能」セクションの Fluent Builder API を参照してください。

非 Web アプリケーションを作成する

すべての Spring アプリケーションが Web アプリケーション (または Web サービス) である必要はありません。main メソッドでコードを実行し、Spring アプリケーションをブートストラップして使用するインフラストラクチャを設定する場合は、Spring Boot の SpringApplication (Javadoc) 機能を使用できます。SpringApplication (Javadoc) は、Web アプリケーションが必要かどうかに応じて、ApplicationContext (Javadoc) クラスを変更します。これを支援するには、まず、サーバー関連の依存関係 (サーブレット API など) をクラスパスから外します。これができない場合 (たとえば、同じコードベースから 2 つのアプリケーションを実行する場合) は、SpringApplication (Javadoc) インスタンスで setWebApplicationType(WebApplicationType.NONE) を明示的に呼び出すか、applicationContextClass プロパティを設定します (Java API 経由または外部プロパティを使用)。ビジネスロジックとして実行するアプリケーションコードは、CommandLineRunner (Javadoc) として実装し、@Bean (Javadoc) 定義としてコンテキストにドロップできます。