自動配置原理-當前版本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. 精髓:
- Spring Boot啟動會載入大量的自動配置類
- 我們看我們需要的功能有沒有SpringBoot預設寫好的自動配置類
- 我們再來看這個自動配置類中配置了哪些元件;沒有需要的元件就自定義一個配置類
- 給容器中自動配置類新增元件的時候,會從properties類中獲取某些屬性。我們就可以在配置檔案中指定這些屬性的值
- 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: 沒有啟用的