SpringBoot的自動配置原理

J,IAT發表於2020-05-30

自動配置原理-當前版本SpringBoot 2.3.0

(純屬個人理解,有理解錯誤的地方還希望大家評論指點)

1. Spring Boot啟動的時候載入主配置類,開啟了自動配置功能 @EnableAutoConfiguration

2. @EnableAutoConfiguration作用:

  • 利用AutoConfigurationImportSelector給容器中匯入一些元件

  • 可以檢視selectImport()方法來檢視匯入哪些元件

    List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
    進入
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
     //SpringFactoriesLoader.loadFactoryNames()掃描所有jar包類路徑下 META-INF/spring.factories
     //把掃描到的這些檔案的內容包裝成properties物件
     //從properties中獲取到EnableAutoConfiguration.class類(類名)對應的值,然後把他們新增到容器中
    
  • 將類路徑下META-INF/spring.factories裡面配置的所有EnableAutoConfiguration的值(97個值)加入到了容器中;

    • 每一個這樣的xxxAutoConfiguration類都是容器中的一個元件,都加入到容器中,用他們來做自動配置

3.每一個自動配置類進行自動配置功能

每一個xxxAutoConfiguration類都為容器新增元件 ,並且都有一個@EnableConfigurationProperties註解,傳入一個對應的配置類

@EnableConfigurationProperties({xxxProperties.class})

每一個自動配置類都定義為xxxproperties ,每個這個的類都各自有@ConfigurationProperties註解,自動繫結對應的配置檔案

@ConfigurationProperties(
    prefix = "xxx",
    ignoreUnknownFields = true
)

4. 以HttpEncodingAutoConfiguration為例解釋自動配置原理

@Configuration  //標註這是一個配置類,以前編寫的配置檔案也一樣,也可以給容器新增元件
@EnableConfigurationProperties({ServerProperties.class}) //啟動指定類的ConfigurationProperties功能;將配置檔案中對應的值和ServerProperties繫結起來,並把ServerProperties加入到容器中
@ConditionalOnWebApplication //Spring底層@Conditional註解,根據不同的條件,如果滿足指定的條件,整個配置類裡面的配置就會生效;判斷當前應用是否是web應用,如果是,當前配置類生效
@ConditionalOnClass({CharacterEncodingFilter.class})//判斷當前專案有沒有這個類CharacterEncodingFilter;SpringMVC中進行解決亂碼解決的過濾器
@ConditionalOnProperty(    //判斷配置檔案中是否存在某個配置server.servlet.encoding.enabled
    //matchIfMissing為true,如果不存在配置,判斷也是成立的
    prefix = "server.servlet.encoding",
    value = {"enabled"},
    matchIfMissing = true
)  //即使我們配置檔案中不配置server.servlet.encoding.enabled=true,也是預設生效的
public class HttpEncodingAutoConfiguration {
    //他已經和springBoot的配置檔案對映了
	private final Encoding properties;

    //只有一個有參構造器的情況下,引數的值就會從容器中拿,引數值在註解@EnableConfigurationProperties({ServerProperties.class})的時候就加入了容器
    public HttpEncodingAutoConfiguration(ServerProperties properties) {
        this.properties = properties.getServlet().getEncoding();
    }
    
    @Bean   //生效了則新增該配置類中定義的元件,這個元件的某些值需要從properties中獲取
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
        return filter;
    }
}

根據當前不同的條件判斷,決定這個配置類是否生效?

Y:@Bean就生效,這個配置類就會給容器中新增各種元件,這些元件的屬性是從對應的properties類中獲取的,這些類裡邊的每一個屬性又是和配置檔案繫結的;

5. 所有配置檔案中能配置的屬性都是在xxxProperties類中封裝的,配置檔案能配置什麼就可以參照某個功能對應的這個屬性類

@ConfigurationProperties(   //從配置檔案中獲取指定的值和bean的屬性進行繫結
    prefix = "server",
    ignoreUnknownFields = true
)
public class ServerProperties {}

6. 精髓:

  1. Spring Boot啟動會載入大量的自動配置類
  2. 我們看我們需要的功能有沒有SpringBoot預設寫好的自動配置類
  3. 我們再來看這個自動配置類中配置了哪些元件;沒有需要的元件就自定義一個配置類
  4. 給容器中自動配置類新增元件的時候,會從properties類中獲取某些屬性。我們就可以在配置檔案中指定這些屬性的值
  5. xxxAutoConfiguration 為自動配置類,給容器中新增元件,它都對應一個xxxProperties 封裝配置檔案中的相關屬性

7. 我們在配置檔案中可以配置的內容

​ 找到某個功能的配置類,去到對應的properties物件中,在@ConfigurationProperties註解中的字首可以找到我們需要的屬性,既可以為其進行配置修改等

//以Cache為例
@ConfigurationProperties(
    prefix = "spring.cache"
)
public class CacheProperties {
    private CacheType type;
    private List<String> cacheNames = new ArrayList();
    private final CacheProperties.Caffeine caffeine = new CacheProperties.Caffeine();
    private final CacheProperties.Couchbase couchbase = new CacheProperties.Couchbase();
    private final CacheProperties.EhCache ehcache = new CacheProperties.EhCache();
    private final CacheProperties.Infinispan infinispan = new CacheProperties.Infinispan();
    private final CacheProperties.JCache jcache = new CacheProperties.JCache();
    private final CacheProperties.Redis redis = new CacheProperties.Redis();

細節

1.@Conditional派生註解

作用:必須是@Conditional指定的條件成立,才給容器中新增元件,配置的內容才生效;

類別 @Conditional 作用(判斷是否滿足當前指定條件)
class條件註解 @ConditionalOnClass 某個class位於類路徑上,才會例項化一個Bean
@ConditionalOnMissingClass 某個class類路徑上不存在的時候,才會例項化一個Bean
Bean條件註解 @ConditionalOnBean 當容器中有指定Bean的條件下進行例項化
@ConditionalOnMissingBean 當容器裡沒有指定Bean的條件下進行例項化
屬性條件註解 @ConditionalOnProperty 當指定的屬性有指定的值時進行例項化
JAVA版本條件 @ConditionalOnJava 系統的java版本是否符合要求
表示式條件註解 @ConditionalOnExpression 基於SpEL表示式的條件判斷,當表示式為true的時候,才會例項化一個Bean。
web條件註解 @ConditionalOnWebApplication 當專案是一個Web專案時進行例項化
………… ………… …………

自動配置類必須在一定條件下才能生效;

我們怎麼知道哪些自動配置類生效:

我們可以在配置檔案中通過啟動debug=true屬性,啟動專案後會在控制檯輸出自動配置報告(CONDITIONS EVALUATION REPORT)

Positive matches: 啟動的

Negative matches: 沒有啟用的

相關文章