Spring Boot中的設定順序
1.概述
在 Spring Boot 應用程式中,多個配置類別通常共存,用於定義 Bean、屬性或整合。雖然 Spring 會自動偵測並處理這些配置,但它不保證它們的處理順序。在配置相互依賴或需要可預測的初始化(例如,先進行資料配置,再進行服務配置)的情況下,控製配置的順序至關重要。
在本教程中,我們將探討 Spring Boot 如何在應用程式啟動期間確定配置順序,以及開發人員如何使用@Order, [@AutoConfigureOrder](https://docs.spring.io/spring-boot/api/java/org/springframework/boot/autoconfigure/AutoConfigureOrder.html) , [@AutoConfigureAfter](https://docs.spring.io/spring-boot/api/java/org/springframework/boot/autoconfigure/AutoConfigureAfter.html) ,和[@AutoConfigureBefore](https://docs.spring.io/spring-boot/api/java/org/springframework/boot/autoconfigure/AutoConfigureBefore.html)等註解來控製配置順序。我們也將解釋常規配置順序和自動配置順序之間的區別,幫助讀者理解每種機制的適用時機和方式。為了鞏固這些概念,本文提供了完全可運行的範例以及單元測試,以展示不同排序策略在實踐中的行為。
2. 理解配置類
Spring 配置類別可以以兩種形式出現:完整配置和精簡配置。 full configuration類別使用@Configuration註解,而lite configuration類別使用@Component, @Import註解,或包含至少一個使用@Bean註解的方法。這兩種類型的配置類別都由 Spring 的ConfigurationClassPostProcessor處理,它會在應用程式啟動階段掃描它們的註解、解釋元資料並註冊相應的 Bean 定義。
3. 配置排序的預設行為
預設情況下,Spring Boot 不保證處理配置類別的順序。它會掃描所有候選類,並根據類路徑找到的配置類別載入它們。
3.1. 無明確順序的範例
下面的程式碼定義了兩個獨立的設定類, ConfigA和ConfigB:
@Configuration
public class ConfigA {
@Bean
public String beanA() {
return "Bean A";
}
}
@Configuration
public class ConfigB {
@Bean
public String beanB() {
return "Bean B";
}
}
這裡,兩個配置都聲明了互不相關的 Bean。當 Spring 加載這些配置時,無論哪個配置類別先被加載,這兩個 Bean 都會被註冊成功。
在執行測試之前,必須驗證兩個 bean 是否存在於上下文中,無論它們的載入順序為何:
@SpringBootTest
class DefaultConfigOrderUnitTest {
@Autowired
private ApplicationContext context;
@Test
void givenConfigsWithoutOrder_whenLoaded_thenBeansExistRegardlessOfOrder() {
assertThat(context.getBean("beanA")).isEqualTo("Bean A");
assertThat(context.getBean("beanB")).isEqualTo("Bean B");
}
}
此測試確認 Spring 確實註冊了這兩個 bean,即使沒有定義特定的順序。容器不強製或依賴任何明確的順序。
3. 使用@Order註解控制順序
有時初始化順序很重要,例如,當一個配置依賴另一個配置的 Bean 時。 @Order註解有助於強制執行可預測的載入順序。
這裡, ConfigOne類別必須在ConfigTwo類別之前載入。我們指定明確的順序值:
@Configuration
@Order(1)
public class ConfigOne {
@Bean
public String configOneBean() {
return "ConfigOneBean";
}
}
@Configuration
@Order(2)
public class ConfigTwo {
@Bean
public String configTwoBean() {
return "ConfigTwoBean";
}
}
由於ConfigTwo ConfigOne雖然該順序不會影響獨立的 bean,但它會在必要時確保依賴關係的順序。
以下單元測試驗證兩個 bean 均已創建,並且由於ConfigOne order 值較小,因此它將在ConfigTwo之前加載。但是,除非一個配置依賴另一個配置,否則無法直接觀察到 bean 的建立順序:
@SpringBootTest(classes = {ConfigTwo.class, ConfigOne.class})
class OrderedConfigUnitTest {
@Autowired
private ApplicationContext context;
@Test
void givenOrderedConfigs_whenLoaded_thenOrderIsRespected() {
String beanOne = context.getBean("configOneBean", String.class);
String beanTwo = context.getBean("configTwoBean", String.class);
assertThat(beanOne).isEqualTo("ConfigOneBean");
assertThat(beanTwo).isEqualTo("ConfigTwoBean");
}
}
即使在測試類中首先聲明了ConfigTwo類,Spring 仍然會先載入ConfigOne ,並遵守順序註解。
4. 使用@DependsOn管理依賴關係
有時,一個 Bean 會明確地依賴另一個 Bean 的初始化。 @DependsOn註解會在 Bean 層級(而非配置層級)強制執行這種依賴關係。讓我們看看一個 Bean 是如何依賴另一個 Bean 的:
@Configuration
public class DependsConfig {
@Bean
public String firstBean() {
return "FirstBean";
}
@Bean
@DependsOn("firstBean")
public String secondBean() {
return "SecondBeanAfterFirst";
}
}
這裡, secondBean依賴firstBean 。 Spring 確保在建立secondBean之前firstBean已完全初始化。
下面的單元測試確保兩個 bean 都已註冊,並且依賴 bean 在其依賴關係之後可用:
@SpringBootTest(classes = DependsConfig.class)
class DependsConfigUnitTest {
@Autowired
private ApplicationContext context;
@Test
void givenDependsOnBeans_whenLoaded_thenOrderIsMaintained() {
String first = context.getBean("firstBean", String.class);
String second = context.getBean("secondBean", String.class);
assertThat(first).isEqualTo("FirstBean");
assertThat(second).isEqualTo("SecondBeanAfterFirst");
}
}
此測試確保兩個 bean 都存在並且按照@DependsOn註解定義的正確順序進行初始化。
5. Spring Boot 中的自動設定順序
Spring Boot 使用自動設定類別來設定應用程式的預設值。當存在多個自動配置時,Spring 使用@AutoConfigureOrder, @AutoConfigureAfter,和@AutoConfigureBefore確定它們的順序。
讓我們進一步探討:
@Configuration
@AutoConfigureOrder(1)
public class FirstAutoConfig {
@Bean
public String autoBeanOne() {
return "AutoBeanOne";
}
}
@Configuration
@AutoConfigureAfter(FirstAutoConfig.class)
public class SecondAutoConfig {
@Bean
public String autoBeanTwo() {
return "AutoBeanTwoAfterOne";
}
}
SecondAutoConfig使用@AutoConfigureAfter確保它在FirstAutoConfig之後載入。這些註解允許 Spring Boot 在內部管理配置順序。
下面的測試確認自動配置的 bean 存在於應用程式上下文中:
@SpringBootTest(classes = {SecondAutoConfig.class, FirstAutoConfig.class})
class AutoConfigOrderUnitTest {
@Autowired
private ApplicationContext context;
@Test
void givenAutoConfigs_whenLoaded_thenOrderFollowsAnnotations() {
String beanOne = context.getBean("autoBeanOne", String.class);
String beanTwo = context.getBean("autoBeanTwo", String.class);
assertThat(beanOne).isEqualTo("AutoBeanOne");
assertThat(beanTwo).isEqualTo("AutoBeanTwoAfterOne");
}
}
即使在測試中SecondAutoConfig在FirstAutoConfig之前列出,註解排序也能確保 Spring 仍然以正確的順序載入它們。
6. 結論
在本文中,我們討論了 Spring Boot 中的配置順序,它是建立可預測和可維護應用程式的重要工具。透過結合使用@Order, @DependsOn,和自動配置註解,開發人員可以精確控制啟動順序並避免初始化衝突。
這些技術確保我們的應用程式上下文一致地加載,無論配置是用戶定義的還是自動配置的。
對於大多數應用程式來說,顯式配置順序是不必要的。 Spring 的依賴解析機制會根據相依性自動處理 Bean 的建立順序。請謹慎使用配置順序,只有當配置處理的順序真正影響應用程式的行為時才需要這樣做。與往常一樣,這些範例的程式碼可以在 GitHub 上找到。