Spring Boot中自動配置Autoconfigure詳解

banq發表於2024-04-10

在本文中,我們將討論 spring-boot-autoconfigure 的內部結構,並學習如何建立我們自己的自動配置。最後,您將瞭解 Spring Boot 的魔力如何發揮作用、spring-boot-autoconfigure 模組的作用,並建立自定義自動配置(並希望能激發您建立自己的自動配置)。

什麼是spring-boot-autoconfigure 
定義了Spring Boot 應用程式啟動期間載入的所有自動配置的類。

這些類具有建立bean的配置,大多基於某些條件。主要條件如下:

  • 類路徑上是否存在依賴項。
  • 是否定義了屬性。
  • bean 是否已由使用者定義。

還有更多的條件,但這些是主要的。它們是使用@Conditional註釋指定的。

@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(JpaRepository.class)
@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class })
@ConditionalOnProperty(prefix = <font>"spring.data.jpa.repositories", name = "enabled", havingValue = "true",
  matchIfMissing = true)
@Import(JpaRepositoriesImportSelector.class)
public class JpaRepositoriesAutoConfiguration {...

  • @AutoConfiguration:說明這是一個自動配置。這與 @Configuration 類似。after 表示該配置應在這兩個配置之後執行。
  • @ConditionalOnBean:僅在已建立 DataSource Bean 的情況下執行此配置。
  • @ConditionalOnClass:JpaRepository 類應存在於 classpath 中,這意味著應存在 spring-data-jpa 依賴關係。
  • @ConditionalOnMissingBean:使用者不應在應用程式中定義指定的 Bean。
  • @ConditionalOnProperty:spring.data.jpa.repositories.enabled 屬性應為 true 或完全未定義。

滿足所有這些條件後,就會建立在該類中定義的 Bean。

有些自動配置類沒有 @Conditional 註解,這意味著它們是無條件配置的。例如,SslAutoConfiguration、ApplicationAvailabilityAutoConfiguration。

探索 spring-boot-autoconfigure 專案可以揭開 Spring Boot 應用程式啟動過程中發生的許多 "魔法 "的神秘面紗。

建立自己的自動配置
您可以為組織中多個專案需要使用的 Bean 建立自動配置。通常情況下,這些 Bean 不是由 Spring 自動配置的,而是您的專案根據前面討論的條件(如類路徑上的依賴關係或屬性值)而需要的。

讓我們嘗試自動配置 rxjava3-jdbc 資料庫 Bean。第一步是建立一個具有自動配置的專案,然後將其作為依賴關係新增到其他專案中。因此,讓我們建立一個包含 rxjava3-jdbc 和 spring-boot-autoconfigure 依賴項的 maven 專案。

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.davidmoten</groupId>
            <artifactId>rxjava3-jdbc</artifactId>
            <version>0.1.4</version>
            <optional>true</optional>
        </dependency>


請注意,rxjava3-jdbc 依賴關係是可選的,因為我們希望使用者自己決定是否要在其專案中使用該依賴關係。如果使用者使用了該依賴關係,則條件將匹配並建立 Bean(想想 @Conditional)。

現在是建立自定義自動配置類的時候了:

@AutoConfiguration
@ConditionalOnClass(Database.class)
@EnableConfigurationProperties(RxJava3JdbcDatabaseProperties.class)
public class RxJava3JdbcDatabaseAutoConfiguration {

    @Bean
    public Database database(RxJava3JdbcDatabaseProperties properties) {
        return Database.nonBlocking()
                .url(properties.getUrl())
                .user(properties.getUsername())
                .password(properties.getPassword())
                .maxPoolSize(properties.getMaxPoolSize())
                .build();
    }
}

請注意 @AutoConfiguration 註解和用於檢查 rxjava3-jdbc 依賴關係中的資料庫類是否在 classpath 上的 @Conditional。如果這些條件匹配,它就會將一些自定義屬性對映到 RxJava3JdbcDatabaseProperties 類,並建立資料庫 Bean。

@ConfigurationProperties(prefix = <font>"rxjava3.jdbc.database")
public class RxJava3JdbcDatabaseProperties {
    private String username;
    private String password;
    private String url;
    private int maxPoolSize;

//getters and setters<i>
...

最後一步是在 src/main/resources/META-INF/spring 下建立一個名為 org.springframework.boot.autoconfigure.AutoConfiguration.imports 的新檔案,並新增自動配置類的全限定名稱:

com.sandeeprai.springboot.autoconfigure.data.rxjava.RxJava3JdbcDatabaseAutoConfiguration

將此專案新增為另一個專案的依賴項,以檢視自動配置的工作情況。

實際操作
要使用自動配置類,請在上述專案中執行 mvn clean install(將其新增到本地 .m2 資源庫),然後在另一個專案中匯入依賴關係。

demo project 建立了一個演示專案,並新增了上述自動配置依賴項和 rxjava3-jdbc,後者包含需要自動配置的資料庫類:

 <dependency>
   <groupId>com.github.davidmoten</groupId>
   <artifactId>rxjava3-jdbc</artifactId>
   <version>0.1.4</version>
  </dependency>

  <dependency>
   <groupId>com.sandeeprai</groupId>
   <artifactId>sandeeprai-spring-boot-autoconfigure</artifactId>
   <version>1.1.0</version>
  </dependency>


主類是一個簡單的 Spring Boot 應用程式主類:

@SpringBootApplication
public class SpringbootAutoconfigureDemoApplication {

 public static void main(String[] args) {
  SpringApplication.run(SpringbootAutoconfigureDemoApplication.class, args);
...

在 application.properties 中新增配置資料庫 Bean 所需的自定義屬性:

rxjava3.jdbc.database.username=sa
rxjava3.jdbc.database.password=sa
rxjava3.jdbc.database.url=jdbc:h2:mem:
rxjava3.jdbc.database.max-pool-size=10

這將配置一個連線到記憶體 h2 資料庫的資料庫 bean。您還需要 h2 依賴關係才能完全執行。

現在使用 --debug 標誌啟動應用程式,在控制檯中檢視 Spring Boot 的自動配置條件評估報告:

============================
CONDITIONS EVALUATION REPORT
============================


Positive matches:
-----------------

   ApplicationAvailabilityAutoConfiguration#applicationAvailability matched:
      - @ConditionalOnMissingBean (types: org.springframework.boot.availability.ApplicationAvailability; SearchStrategy: all) did not find any beans (OnBeanCondition)
...

   RxJava3JdbcDatabaseAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.davidmoten.rxjava3.jdbc.Database' (OnClassCondition)
...

Negative matches:
-----------------

   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'jakarta.jms.ConnectionFactory' (OnClassCondition)
...

Exclusions:
-----------

    None


Unconditional classes:
----------------------

    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
...

這將列出建立的每個自動配置 Bean、未建立的 Bean、每個正負匹配的原因、排除項和無條件自動配置的 Bean。由於我們包含了 rxjava3-jdbc 依賴項,因此正匹配列表中包括了我們的自定義自動配置 Bean。如果移除依賴關係並重新執行專案,它應該會出現在否定匹配部分。


問:我應該在自動配置類上使用 @AutoConfiguration 還是 @Configuration 註解?
答:根據 Spring Boot 的釋出說明,@AutoConfiguration 應用於註解頂級自動配置類。註解本身並不會使類成為自動配置的候選類。您仍然需要將其新增到前面提到的 org.springframework.boot.autoconfigure.AutoConfiguration.imports 檔案中。在這方面,它與 @Configuration 類似(javadoc 也說明了這一點:除了 ConfigurationproxyBeanMethods() proxyBeanMethods 始終為 false 之外,自動配置類是常規的 @Configuration)。不過,@AutoConfiguration 在此上下文中更有意義,它是目前的標準,並明確表示該類是用於自動配置的。

問:我應該將自定義自動配置類新增到 org.springframework.boot.autoconfigure.AutoConfiguration.imports 還是 spring.factories 檔案中?
答:儘管許多教程都提到要使用 spring.factories 檔案,但根據 Spring Boot 的釋出說明,該檔案已被棄用,而應使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 檔案。

問:何時應建立和使用自定義自動配置?
答:如果 Spring Boot 不會自動配置某個 Bean,而該 Bean 在您組織的多個專案中使用,並且需要根據特定條件進行配置,則應建立自定義自動配置。對於更簡單的情況,可以在應用程式程式碼中使用 @Configuration 類。

​​​​​​​原始碼:GitHub.

相關文章