SpringBoot-自動配置原理(七)

自動配置原理

本節內容分爲三個部分java

  • 配置文件的寫法
  • 分析自動配置原理
  • @Conditional

一. 配置文件的寫法

配置文件能夠寫什麼?web

是與/META-INF/spring.factories配置文件相關聯,在該文件中,咱們經過源碼能夠找到面試

咱們在配置文件中要寫的配置spring

二 .分析自動配置原理

1.SpringBoot啓動的時候加載主配置類,開啓了自動配置功能 @EnableAutoConfigurationspringboot

2.@EnableAutoConfiguration 做用 :mvc

  • 利用EnableAutoConfigurationImportSelector給容器中導入一些組件,導入了哪些組件呢?app

  • 能夠查看這個類selectImports()方法的內容,他返回了一個 autoConfigurationEntry , 來自 this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); 這個方法。咱們繼續跟蹤;this

  • 這個方法中有一個值 : List configurations = this.getCandidateConfigurations(annotationMetadata, attributes); 叫作獲取候選的配置 , 咱們點擊去繼續跟蹤; 編碼

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

    這裏裏面有一個 SpringFactoriesLoader.loadFactoryNames() ,咱們繼續進去看 , 它又調用了 loadSpringFactories 方法;繼續跟蹤。發現它去得到了一個資源文件:"META-INF/spring.factories"url

    Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");

    繼續閱讀源碼 , 它將讀取到的資源封裝在url中,而後遍歷url , 將這些url文件封裝在Properties文件中;最後返回封裝好的結果;他的那個ClassLoader參數,咱們追蹤回去,看到他就是 EnableAutoConfiguration ;

  • 說明了這個邏輯就是 從properties中獲取到EnableAutoConfiguration.class類(類名)對應的值,而後把他們添加在容器中

  • 總結一句話就是:將類路徑下 META-INF/spring.factories 裏面配置的全部EnableAutoConfiguration的值加入到了容器中;咱們從源碼中拿過來

每個這樣的 xxxAutoConfiguration類都是容器中的一個組件,最後都加入到容器中;用他們來作自動配置;

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

4.咱們以HttpEncodingAutoConfiguration(Http編碼自動配置)爲例解釋自動配置原理;

@Configuration //表示這是一個配置類,之前編寫的配置文件同樣,也能夠給容器中添加組件

//啓動指定類的ConfigurationProperties功能;
//進入這個HttpProperties查看,將配置文件中對應的值和HttpProperties綁定起來;
//並把HttpProperties加入到ioc容器中
@EnableConfigurationProperties({HttpProperties.class}) 

//Spring底層@Conditional註解
//根據不一樣的條件判斷,若是知足指定的條件,整個配置類裏面的配置就會生效;
//這裏的意思就是判斷當前應用是不是web應用,若是是,當前配置類生效
@ConditionalOnWebApplication(
    type = Type.SERVLET
)

//判斷當前項目有沒有這個類CharacterEncodingFilter;SpringMVC中進行亂碼解決的過濾器;
@ConditionalOnClass({CharacterEncodingFilter.class})

//判斷配置文件中是否存在某個配置:spring.http.encoding.enabled;
//若是不存在,判斷也是成立的
//即便咱們配置文件中不配置spring.http.encoding.enabled=true,也是默認生效的;
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)

public class HttpEncodingAutoConfiguration {

    //他已經和SpringBoot的配置文件映射了
    private final Encoding properties;

    //只有一個有參構造器的狀況下,參數的值就會從容器中拿
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }

    //給容器中添加一個組件,這個組件的某些值須要從properties中獲取
    @Bean
    @ConditionalOnMissingBean //判斷容器沒有這個組件?
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }
    。。。。。。
}

一句話總結 : 根據當前不一樣的條件判斷,決定這個配置類是否生效!

一但這個配置類生效;這個配置類就會給容器中添加各類組件;這些組件的屬性是從對應的properties類中獲取的,這些類裏面的每個屬性又是和配置文件綁定的;

5.全部在配置文件中能配置的屬性都是在xxxxProperties類中封裝者‘;配置文件能配置什麼就能夠參照某個功能對應的這個屬性類

@ConfigurationProperties(
    prefix = "spring.http"
) //從配置文件中獲取指定的值和bean的屬性進行綁定
public class HttpProperties {
    private boolean logRequestDetails;
    private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();

    public HttpProperties() {
    }

    public boolean isLogRequestDetails() {
        return this.logRequestDetails;
    }

    public void setLogRequestDetails(boolean logRequestDetails) {
        this.logRequestDetails = logRequestDetails;
    }

    public HttpProperties.Encoding getEncoding() {
        return this.encoding;
    }

    public static class Encoding {
        public static final Charset DEFAULT_CHARSET;
        private Charset charset;
        private Boolean force;
        private Boolean forceRequest;
        private Boolean forceResponse;
        private Map<Locale, Charset> mapping;
        
        、、、、、、
    }
}

咱們去配置文件裏面試試前綴,看提示!

這就是自動裝配的原理!

精髓:

1)、SpringBoot啓動會加載大量的自動配置類

2)、咱們看咱們須要的功能有沒有在SpringBoot默認寫好的自動配置類當中;

3)、咱們再來看這個自動配置類中到底配置了哪些組件;(只要咱們要用的組件存在在其中,咱們就不須要再手動配置了)

4)、給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性。咱們只須要在配置文件中指定這些屬性的值便可;

xxxxAutoConfigurartion:自動配置類;向容器中添加組件

xxxxProperties:封裝配置文件中相關屬性;修改配置,就是咱們的application.yml(properties)配置文件

@ConditionalXxx的存在,會屏蔽組件,必須符合必定的條件才生效

例如:spring.mvc的屬性配置

全部能配置的屬性都在這裏

或者咱們在META-INF/spring.factories文件下找到Mvc相關的

三 . @Conditional

瞭解完自動裝配的原理後,咱們來關注一個細節問題 ,自動配置類必須在必定的條件下才能生效;

@Conditional派生註解(Spring註解版原生的@Conditional做用)

做用:必須是@Conditional指定的條件成立,纔給容器中添加組件,配置配裏面的全部內容才生效;

那麼多的自動配置類,必須在必定的條件下才能生效;也就是說,咱們加載了這麼多的配置類,但不是全部的都生效了。

咱們怎麼知道哪些自動配置類生效;咱們能夠經過啓用 debug=true屬性;來讓控制檯打印自動配置報告,這樣咱們就能夠很方便的知道哪些自動配置類生效;

#開啓springboot的調試類
debug=true

Positive matches:(自動配置類啓用的:正匹配)

Negative matches:(沒有啓動,沒有匹配成功的自動配置類:負匹配)

Unconditional classes: (沒有條件的類)

輸出的日誌咱們能夠在這裏看下:控制檯打印日誌

相關文章
相關標籤/搜索