原文出處: 晴楓
1 SpringBoot運(yùn)作原理
上一章中我們提到主程序類的注解 @SpringBootApplication 注解拌蜘,它其實(shí)是個(gè)組合注解预麸,源碼如下:
@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 {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
}
最主要的還是三個(gè)配置 @SpringBootConfiguration于置、@EnableAutoConfigration、@ComponentScan 三個(gè)注解,下面我們來(lái)一一分析。
1.1 @SpringBootConfiguration
查看@SpringBootConfiguration源碼惫叛,其實(shí)它也就是@Configuration注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
對(duì)于 @Configuration,我們并不陌生逞刷,它就是 JavaConfig 形式的 SpringIOC 容器的配置類挣棕,也是 SpringBoot 推薦使用配置形式,所以主程序類標(biāo)注了 @SpringBootConfiguration 注解亲桥,其本身也就是一個(gè)配置類。更多有關(guān) JavaConfig 形式的配置以及有關(guān)它和 XML 形式的配置的區(qū)別與聯(lián)系固耘,請(qǐng)參考后續(xù)有關(guān) Spring 注解版相關(guān)文章题篷。
1.2 @ComponentScan
@ComponentScan 注解在 Spring 的注解中也起到到相當(dāng)重要的作用,它可以自定義 Spring 掃描的包厅目,也就是它默認(rèn)會(huì)掃描標(biāo)注了 @Controller番枚、@Service法严、@Component 以及 @Repository 注解的類,并實(shí)例化這些組件到 SpringIOC 容器中葫笼,它有個(gè)配置屬性: basePackages深啤,也就是指定掃描的包,如果不知道路星,它會(huì)默認(rèn)掃描配置了該注解的類的包所在的路徑(包括子包)溯街。我們看 @SpringBootConfiguration 注解的源碼中有段代碼:
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
scanBasePackages 屬性,指定到了 @ComponentScan 注解的 basePackages 屬性洋丐,所有在 SpringBoot 中呈昔,我們同樣可以通過(guò) scanBasePackages 屬性指定包掃描的路徑(如部指定,會(huì)默認(rèn)掃描主程序類所在的包路徑以及子包下的類):
@SpringBootApplication(scanBasePackages = "com.seagetech.springbootdemo")
1.3 @EnableAutoConfigration
關(guān)于 SpringBoot 的運(yùn)作原理友绝,它的核心功能還是由 @EnableAutoConfigration 注解提供堤尾,所有把它放到最后來(lái)講,我們來(lái)看下它的源碼:
@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 {};
}
1.3.1 @AutoConfigurationPackage
這個(gè)注解的主要功能自動(dòng)配置包迁客,它會(huì)獲取主程序類所在的包路徑郭宝,并將包路徑(包括子包)下的所有組件注冊(cè)到 SpringIOC 容器中。
1.3.2 @Import({AutoConfigurationImportSelector.class})
@EnableAutoConfiguration 的關(guān)鍵功能也是這個(gè) @Import 導(dǎo)入的配置功能掷漱,使用 SpringFactoriesLoader.loadFactoryNames 方法來(lái)掃描具有 META-INF/spring.factories 文件的jar包粘室,我們看看在 spring-boot-autoconfigure-2.10.RELEASE.jar 包的 META-INF 下正好有個(gè) spring.factories 文件:
打開 spring.factories 文件,找到 org.springframework.boot.autoconfigure.EnableAutoConfiguration 指定的自動(dòng)配置類:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
......
......
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
每一個(gè) xxxAutoConfiguration 類都是容器中的一個(gè)組件切威,都加入到容器中育特,用它們來(lái)做自動(dòng)配置。
2 自動(dòng)配置分析
在上一節(jié)基礎(chǔ)上先朦,我們知道每一個(gè)自動(dòng)配置類進(jìn)行自動(dòng)配置功能缰冤,下面我們以 HttpEncodingAutoConfiguration 為例來(lái)分析:
2.1 配置參數(shù)
@ConfigurationProperties(
prefix = "spring.http"http://①
)
public class HttpProperties {
private boolean logRequestDetails;
private final HttpProperties.Encoding encoding = new HttpProperties.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;
public Encoding() {
this.charset = DEFAULT_CHARSET;//②
}
......
static {
DEFAULT_CHARSET = StandardCharsets.UTF_8;//②
}
......
}
代碼解析:
- 在 application.properties 文件中配置的時(shí)候指定前綴是 spring.http;
- 指定默認(rèn)的編碼方式是 UTF-8喳魏,如果需要修改棉浸,可使用 spring.http.encoding.charset=編碼。
2.2 自動(dòng)配置類
@Configuration//①
@EnableConfigurationProperties({HttpProperties.class})//②
@ConditionalOnWebApplication(
type = Type.SERVLET
)//③
@ConditionalOnClass({CharacterEncodingFilter.class})//④
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)//⑤
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
......
}
.......
}
源碼解析:
- 表示這是一個(gè)配置類刺彩,以前編寫的配置文件一樣迷郑,也可以給容器中添加組件。
- 啟動(dòng)指定類的 ConfigurationProperties 功能创倔,將配置文件中對(duì)應(yīng)的值和 HttpEncodingProperties 綁定起來(lái)嗡害;并把 HttpEncodingProperties 加入到 IOC 容器中;
- Spring 底層 @Conditional 注解(有關(guān) @Conditional 注解的詳解請(qǐng)參考后續(xù) Spring 注解相關(guān)文章)畦攘,根據(jù)不同的條件霸妹,如果滿足指定的條件,整個(gè)配置類里面的配置就會(huì)生效知押,該注解是判斷當(dāng)前應(yīng)用是否是web應(yīng)用叹螟,如果是鹃骂, HttpEncodingAutoConfiguration 配置類生效;
- 判斷當(dāng)前項(xiàng)目有沒有這個(gè)類 CharacterEncodingFilter罢绽;SpringMVC 中進(jìn)行亂碼解決的過(guò)濾器畏线,如果有則 HttpEncodingAutoConfiguration 配置生效;
- 判斷 application.properties 配置文件中是否存在 spring.http.encoding.enabled良价,如果不存在寝殴,判斷也是成立的,因?yàn)?matchIfMissing=true棚壁,即缺省時(shí)默認(rèn)為 true杯矩。
根據(jù)當(dāng)前不同的條件判斷,決定 HttpEncodingAutoConfiguration 這個(gè)配置類是否生效袖外?一但這個(gè)配置類生效史隆;這個(gè)配置類就會(huì)給容器中添加各種組件,這些組件的屬性是從對(duì)應(yīng)的 HttpEncodingProperties 類中獲取的曼验,這些類里面的每一個(gè)屬性又是和配置文件綁定的泌射。
2.3 @Conditional擴(kuò)展注解
除了以上解析到的注解,SpringBoot 還為我們提供了更多的有關(guān) @Conditional 的派生注解鬓照。它們的作用:必須是 @Conditional 指定的條件成立熔酷,才給容器中添加組件,配置配里面的所有內(nèi)容才生效: