Spring Boot 應用程式

本節包含與 Spring Boot 應用程式直接相關的主題。

建立您自己的 FailureAnalyzer

FailureAnalyzer 是一種在啟動時攔截異常並將其轉換為人類可讀訊息(封裝在 FailureAnalysis 中)的好方法。Spring Boot 為與應用上下文相關的異常、JSR-303 驗證等提供了此類分析器。您也可以建立自己的分析器。

AbstractFailureAnalyzerFailureAnalyzer 的一個便捷擴充套件,它檢查要處理的異常中是否存在指定的異常型別。您可以從它繼承,以便您的實現在異常實際存在時才有機會處理它。如果由於某種原因無法處理異常,請返回 null,以便讓其他實現有機會處理該異常。

FailureAnalyzer 實現必須註冊在 META-INF/spring.factories 中。以下示例註冊 ProjectConstraintViolationFailureAnalyzer

org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
如果需要訪問 BeanFactoryEnvironment,請在您的 FailureAnalyzer 實現中將它們宣告為建構函式引數。

自動配置疑難解答

Spring Boot 自動配置會盡力“做正確的事情”,但有時會失敗,而且很難找出原因。

在任何 Spring Boot ApplicationContext 中都有一個非常有用的 ConditionEvaluationReport 可用。如果您啟用 DEBUG 日誌輸出,就可以看到它。如果您使用 spring-boot-actuator(請參閱 Actuator 部分),還有一個 conditions 端點,它以 JSON 格式呈現報告。使用該端點來除錯應用程式,並檢視 Spring Boot 在執行時添加了哪些功能(以及哪些沒有新增)。

透過檢視原始碼和 API 文件可以回答更多問題。閱讀程式碼時,請記住以下經驗法則:

  • 查詢名為 *AutoConfiguration 的類並閱讀其原始碼。特別注意 @Conditional* 註解,以瞭解它們何時以及啟用了哪些功能。在命令列或系統屬性 -Ddebug 中新增 --debug,以在控制檯上獲取您的應用程式中所有自動配置決策的日誌。在啟用 Actuator 的執行中的應用程式中,檢視 conditions 端點(/actuator/conditions 或其 JMX 等效項)以獲取相同資訊。

  • 查詢帶有 @ConfigurationProperties 註解的類(例如 ServerProperties),並從中讀取可用的外部配置選項。@ConfigurationProperties 註解有一個 name 屬性,用作外部屬性的字首。因此,ServerPropertiesprefix="server",其配置屬性是 server.portserver.address 等。在啟用 Actuator 的執行中的應用程式中,檢視 configprops 端點。

  • 查詢 Binder 上的 bind 方法的使用,以寬鬆的方式從 Environment 中顯式提取配置值。它通常與字首一起使用。

  • 查詢直接繫結到 Environment@Value 註解。

  • 查詢 @ConditionalOnExpression 註解,它們響應 SpEL 表示式來開啟或關閉功能,SpEL 表示式通常是透過 Environment 解析佔位符後評估的。

在 Environment 或 ApplicationContext 啟動前對其進行自定義

一個 SpringApplicationApplicationListenerApplicationContextInitializer 實現,用於對上下文或環境應用自定義。Spring Boot 會從 META-INF/spring.factories 內部載入許多此類自定義。註冊更多自定義有不止一種方式:

  • 透過程式設計方式,針對每個應用程式,透過在執行 SpringApplication 之前呼叫其 addListenersaddInitializers 方法。

  • 透過宣告方式,針對所有應用程式,透過新增 META-INF/spring.factories 並將應用程式都用作庫的 jar 檔案打包。

SpringApplication 會向監聽器傳送一些特殊的 ApplicationEvents(有些甚至在上下文建立之前傳送),然後也會註冊監聽器來監聽由 ApplicationContext 釋出 的事件。有關完整列表,請參閱“Spring Boot 特性”部分中的 應用程式事件和監聽器

還可以透過使用 EnvironmentPostProcessor 在應用程式上下文重新整理之前自定義 Environment。每個實現都應該在 META-INF/spring.factories 中註冊,如下例所示:

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

實現可以載入任意檔案並將其新增到 Environment 中。例如,以下示例從 classpath 中載入 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 已經預先準備好了 Spring Boot 預設載入的所有常用屬性源。因此,可以從環境中獲取檔案的位置。前面的示例將 custom-resource 屬性源新增到列表末尾,以便在任何其他常規位置定義的鍵優先。自定義實現可以定義不同的順序。
雖然在您的 @SpringBootApplication 上使用 @PropertySource 可能看起來是在 Environment 中載入自定義資源的便捷方式,但我們不推薦這樣做。這些屬性源直到應用程式上下文正在重新整理時才新增到 Environment 中。這對於配置某些屬性(例如 logging.*spring.main.*)來說太晚了,這些屬性在重新整理開始之前就被讀取了。

構建 ApplicationContext 層次結構(新增父上下文或根上下文)

您可以使用 SpringApplicationBuilder 類建立父/子 ApplicationContext 層次結構。有關更多資訊,請參閱“Spring Boot 特性”部分中的 Fluent Builder API

建立非 Web 應用程式

並非所有 Spring 應用程式都必須是 Web 應用程式(或 Web 服務)。如果您想在 main 方法中執行一些程式碼,同時也引導一個 Spring 應用程式來設定基礎設施,您可以使用 Spring Boot 的 SpringApplication 特性。SpringApplication 會根據它是否認為需要 Web 應用程式來改變其 ApplicationContext 類。您可以做的第一件事就是將與伺服器相關的依賴項(例如 servlet API)排除在 classpath 之外。如果不能這樣做(例如,如果您從同一個程式碼庫執行兩個應用程式),那麼您可以顯式地在您的 SpringApplication 例項上呼叫 setWebApplicationType(WebApplicationType.NONE),或者設定 applicationContextClass 屬性(透過 Java API 或外部屬性)。您希望作為業務邏輯執行的應用程式程式碼可以實現為 CommandLineRunner,並作為 @Bean 定義放入上下文中。