Spring Boot 應用程式
本節包含與 Spring Boot 應用程式直接相關的主題。
建立您自己的 FailureAnalyzer
FailureAnalyzer 是一種攔截啟動異常並將其轉換為人類可讀訊息(封裝在 FailureAnalysis 中)的絕佳方式。Spring Boot 為與應用程式上下文相關的異常、JSR-303 驗證等提供了此類分析器。您也可以建立自己的分析器。
AbstractFailureAnalyzer 是 FailureAnalyzer 的一個便捷擴充套件,它檢查異常中是否存在指定的異常型別。您可以從該類擴充套件,以便您的實現只有在實際存在異常時才有機會處理該異常。如果由於某種原因您無法處理該異常,請返回 null,讓其他實現有機會處理該異常。
FailureAnalyzer 實現必須在 META-INF/spring.factories 中註冊。以下示例註冊 ProjectConstraintViolationFailureAnalyzer
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
如果您需要訪問 BeanFactory 或 Environment,請在您的 FailureAnalyzer 實現中將它們宣告為建構函式引數。 |
自動配置疑難解答
Spring Boot 自動配置會盡力“做正確的事”,但有時會失敗,而且很難說出原因。
在任何 Spring Boot ApplicationContext 中都有一個非常有用的 ConditionEvaluationReport。如果啟用 DEBUG 日誌輸出,您可以看到它。如果您使用 spring-boot-actuator(請參閱Actuator部分),還有一個 conditions 端點,它以 JSON 格式呈現報告。使用該端點除錯應用程式並檢視 Spring Boot 在執行時添加了哪些功能(以及哪些未新增)。
透過檢視原始碼和 API 文件可以回答更多問題。閱讀程式碼時,請記住以下經驗法則
-
查詢名為
*AutoConfiguration的類並閱讀其原始碼。特別注意@Conditional*註解,以找出它們何時啟用哪些功能。在命令列中新增--debug或系統屬性-Ddebug,以在控制檯上獲取應用程式中所有自動配置決策的日誌。在啟用了 actuator 的執行中應用程式中,檢視conditions端點(/actuator/conditions或等效的 JMX)以獲取相同的資訊。 -
查詢帶有
@ConfigurationProperties的類(例如ServerProperties),並從中讀取可用的外部配置選項。@ConfigurationProperties註解有一個name屬性,它充當外部屬性的字首。因此,ServerProperties的prefix="server",其配置屬性為server.port、server.address等。在啟用了 actuator 的執行中應用程式中,檢視configprops端點。 -
查詢
Binder上bind方法的使用,以寬鬆地顯式從Environment中提取配置值。它通常與字首一起使用。 -
查詢直接繫結到
Environment的@Value註解。 -
查詢
@ConditionalOnExpression註解,這些註解根據 SpEL 表示式(通常透過從Environment解析的佔位符進行評估)開啟和關閉功能。
在應用程式上下文啟動前自定義環境或應用程式上下文
一個 SpringApplication 具有 ApplicationListener 和 ApplicationContextInitializer 實現,用於對上下文或環境應用自定義。Spring Boot 從 META-INF/spring.factories 內部載入了許多此類自定義。註冊附加自定義的方法不止一種
-
透過在執行
SpringApplication之前呼叫其addListeners和addInitializers方法,以程式設計方式為每個應用程式新增。 -
透過新增
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 中。例如,以下示例從類路徑載入 YAML 配置檔案
-
Java
-
Kotlin
import java.io.IOException;
import org.springframework.boot.EnvironmentPostProcessor;
import org.springframework.boot.SpringApplication;
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(), () -> "'path' [%s] must exist".formatted(path));
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.EnvironmentPostProcessor
import org.springframework.boot.SpringApplication
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 功能”部分中的流式構建器 API。
建立非 Web 應用程式
並非所有 Spring 應用程式都必須是 Web 應用程式(或 Web 服務)。如果您想在 main 方法中執行一些程式碼,同時引導一個 Spring 應用程式來設定要使用的基礎設施,您可以使用 Spring Boot 的 SpringApplication 功能。SpringApplication 會根據它認為是否需要 Web 應用程式來更改其 ApplicationContext 類。您可以做的第一件事是避免將與伺服器相關的依賴項(例如 servlet API)排除在類路徑之外。如果無法做到這一點(例如,如果您從同一個程式碼庫執行兩個應用程式),那麼您可以顯式呼叫 SpringApplication 例項上的 setWebApplicationType(WebApplicationType.NONE) 或設定 applicationContextClass 屬性(透過 Java API 或外部屬性)。您希望作為業務邏輯執行的應用程式程式碼可以實現為 CommandLineRunner 並作為 @Bean 定義放入上下文中。