SpringBoot自動配置原理
本節主要分析:
- 核心註解SpringBootApplication註解
- EnableAutoConfiguration自動配置的原始碼分析
1 SpringBootApplication註解
@SpringBootApplication,標識某個類上說明這個類是 SpringBorn的主配置類。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication
1.1 @ SpringBootConfiguration: Spring Boot的配置類
標註在某個類上,表示這是一個 Spring boot的配置類;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@ Configuration配罩類上來標註這個註解; 配置類---配置檔案。配置類,本質上也是容器中的一個元件;@ Component
1.2 @ EnableAutoConfiguration:開啟自動配置功能
以前我們需要配置的東西, Spring boot幫我們自動配置;@ EnableAuto Configuration告訴Springboot開啟自動配置功能:這樣自動配置才能生效。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
@ AutoConfigurationPackage:自動配置包
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@Import({Registrar.class})
Spring的底層註解@Import,給容器中匯入一個元件;匯入的元件由AutoConfigurationPackages. Registrar. class
主要作用是:將主配置類(@ Spring BootApplicationa標註的類)的所在包及下面所有子包裡面的所有元件掃描到 Spring容器
@Import({AutoConfigurationImportSelector.class}) 給容器匯入元件。
AutoConfigurationImportSelector :匯入哪些元件的選擇器。將所有需要匯入的元件以全類名的方式返回;這些元件就會被新增到容器中。會給容器中匯入非常多的自動配置類( XXXAutoConfiguration),並配置號這些元件。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
Spring Boot在啟動的時候從類路徑下的 META-INF/spring.factories中獲取 EnableAutoConfiguration指定的值,將這些值封裝成Properties物件,並返回給載入器。
而外部傳入的class是EnableAutoConfiguration.class,也就是說從 properties中獲取到EnableAutoConfiguration.class類對應的很多配置載入到容器中,每個配置都是自動配置類xxxAutoConfigration。每個Configuration類作為容器的元件載入到容器中,進行自動配置。
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader)
以HttpEncodingAutoConfiguration為例,自動配置類上有多個註解。所有配置類的屬性都在xxProperties類中封裝,配置類配置了什麼功能可以參考屬性檔案。
// 標識配置類
@Configuration
// 啟用ConfigurationProperties功能呢,繫結HttpProperties屬性類,注入到IOC容器中
@EnableConfigurationProperties(HttpProperties.class)
// conditional是spring底層註解,滿足指定條件,則配置類中的配置才會生效
// 本例中是滿足web應用時,配置生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
// 判斷是否有CharacterEncodingFilter過濾器
@ConditionalOnClass(CharacterEncodingFilter.class)
// 判斷是否存在某個配置spring.http.encoding.enabled,如果沒有配置這條屬性,預設生效
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final HttpProperties.Encoding properties;
// 指定使用HttpProperties中的Encoding屬性
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
// 返回Bean,使用properties
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
}
如果AutoConfiguration類的所有條件都滿足,就會執行自動配置,建立Bean注入到容器中。由此可見,META-INF/spring.factories的EnableAutoConfiguration屬性配置了很多自動配置類名,並不是所有的都生效。
一但這個配置類生效;這個配置類就會給容器中新增各種元件:這些元件的屬性是從對應的 properties類中獲取的,這些類裡面的每一個屬性又是和配置檔案繫結的。我們在專案配置檔案中能配置下面的屬性,屬性來源主要是HttpProperties屬性繫結類。
spring.http.encoding.enabled=true
spring.http.encoding.charset=utf-8
spring.http.encoding.force=true
J2E的整體整合解決方案和自動配置都在 spring-boot-autoconfigure-2.XX. RELEASE. jar;
SpringBoot自動配置的總結與運用
SpringBoot啟動時會載入大量自動配置類,我們根據需要的功能檢視springboot是否預設自動配置,如果用到的元件已經載入,就不用自己配置了。springboot自動配置類新增元件時,會從properties類中獲取某些屬性。如果對這些預設屬性不滿意,可以在專案配置檔案中自定義配置。
@ Conditional派生註解( spring註解版原生的@Conditional作用)
作用:必須是@Conditional指定的條件成立,才給容器中新增元件,配置配裡面的所有內容才生效。自動配置類必須在一定條件下才生效,例如上面的HttpEncodingAutoConfiguration自動配置類必須滿足是web應用,具有編碼過濾器,並且沒有該bean時才生成。
然而,如果對於每個配置類都要挨個查是否生效配置,效率太差。我們可以啟動springboot的debug屬性,在控制檯列印自動配置報告。
debug:
true
Positive matches:生效
Negative matches:未生效