Spring Boot 自動設定一篇概覽

2023-05-29 06:00:55

一、什麼是自動設定 bean

自動設定類通過新增 @AutoConfiguration 註解實現。

因為 @AutoConfiguration 註解本身是以 @Configuration 註解的,所以自動設定類可以算是一個標準的基於 @Configuration 註解的類。

@Conditional 註解可以用於宣告自動設定啟用條件,通常,我們可以使用 @ConditionalOnClass、@ConditionalOnMissingBean 註解。

二、自動設定發現

Spring Boot 通過檢查【META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports】組態檔獲取自動設定類。

檔案內包含自定義的自動設定類全限定名,每行一個。

範例如下:

com.mycorp.libx.autoconfigure.LibXAutoConfiguration
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration  

1、關於約定:

自動設定類必須通過如上組態檔引入。

合理規劃其放置包位置,避免被自動包掃描。

內部不要設定自動包掃描,如需要可以使用 @Import 引入。

2、關於順序

明確的物件先後順序可以通過設定 @AutoConfiguration 的 before、beforeName、after、afterName 屬性,或者使用 @AutoConfigurationBefore、@AutoConfigurationAfter 註解實現。例如 web 服務類設定需要置於 @WebMvcAutoConfiguration 註解之後。

如果沒有明確的先後順序,也可以使用 @AutoConfigureOrder 註解宣告順序。類似 @ Order 註解,不同之處在於其只作用於自動設定類。

三、條件註解

1、類條件

@ConditionalOnClass、@ConditionalOnMissingClass 

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnClassCondition.class})
public @interface ConditionalOnClass {
    Class<?>[] value() default {};

    String[] name() default {};
}

註解後設資料是通過 ASM 處理的,所以可以通過 value 屬性傳遞 Class 型別引數,或者也可以通過 name 傳遞類全限定名作為引數。

無效情景:

@Bean 註解的方法,其返回值型別為類目標條件類本身。在方法上的條件判正之前,JVM 已經載入了相關的類,並且很可能會執行相關的方法參照,如果類不存在的話,就會導致失敗。

為了處理此類情景,需要新增額外的 @Configuration 註解,使用如下:

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@AutoConfiguration
// Some conditions ...
public class MyAutoConfiguration {

    // Auto-configured beans ...

    @Configuration(proxyBeanMethods = false) // 
    @ConditionalOnClass(SomeService.class)
    public static class SomeServiceConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public SomeService someService() {
            return new SomeService();
        }

    }

}

 2、Bean 條件

@ConditionalOnBean、ConditionalOnMissingBean 
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnBeanCondition.class})
public @interface ConditionalOnBean {
    Class<?>[] value() default {};

    String[] type() default {};

    Class<? extends Annotation>[] annotation() default {};

    String[] name() default {};

    SearchStrategy search() default SearchStrategy.ALL;

    Class<?>[] parameterizedContainer() default {};
}
search 屬性用於限定搜尋範圍。
作用於 @Bean 註解的方法時,預設的目標 Bean 型別為方法的返回值型別。如下:
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;

@AutoConfiguration
public class MyAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public SomeService someService() {
        return new SomeService();
    }

}

條件註解的判正會受 Bean 定義的註冊、處理順序影響,這點需要特別關注。通常建議只在自動設定類上使用條件註解。

@ConditionalOnBean、ConditionalOnMissingBean 條件註解的 @Configuration 類依然會被建立,只不是不會被註冊。

當使用 @Bean 註解方法時,返回值最好使用具體的類,而不要使用介面。這一點,對於使用基於 Bean 型別判定的條件註解時尤為重要。

3、屬性條件

@ConditionalOnProperty 基於 Spring 的環境變數判正。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnPropertyCondition.class})
public @interface ConditionalOnProperty {
    String[] value() default {};

    String prefix() default "";

    String[] name() default {};

    String havingValue() default "";

    boolean matchIfMissing() default false;
} 

 可以基於字首或者特定名稱來判斷。

 4、資源條件

@ConditionalOnResource 基於是否存在特定的資源來判正,如:判定資源「file:/home/user/test.dat」。

5、Web 應用條件

@ConditionalOnWebApplication、@ConditionalOnNotWebApplication
基於當前是否為 Web 應用。
@ConditionalOnWarDeployment、@ConditionalOnNotWarDeployment 判定當前應用是否為傳統的部署到 servlet 容器的 WAR 包應用,區別於內嵌的 web 伺服器應用。

四、構建 starter

一個典型的 Spring Boot starter 包括如下兩點:

  • autoconfigure 模組:包含自動設定相關程式碼。

  • starter 模組:提供 autoconfigure 模組所需的依賴及其它附屬依賴。

1、命名

不要以 spring-boot 做字首,這是官方保留使用。

以自有工程名做字首,並附加資訊體現其用途。

2、設定鍵

設定鍵需要提供專門的名稱空間,不要使用 Spring Boot 官方名稱空間,

3、autoconfigure 模組

包含使用依賴的所有設定,也可以包括設定鍵定義及自定義元件初始化的回撥介面。

所有引入應該做成可設定的,並且預設為不使用。

Spring Boot 使用註解處理器來收集位於組態檔(META-INF/spring-autoconfigure-metadata.properties)中的自動設定條件,快速過濾掉不需要自動設定的,以加快啟動速度。

如果使用 Maven 管理專案,則需要加入如下依賴來處理啟用自動設定功能:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure-processor</artifactId>
    <optional>true</optional>
</dependency>  

4、starter 模組

提供依賴。顯示宣告所有必需的依賴,對於可選的,不要宣告。