SpringBoot(二)自動配置

請叫我王蜀黍發表於2018-07-23

使用starter簡化依賴配置

Spring提供了一系列starter來簡化Maven配置。其核心原理也就是Maven和Gradle的依賴傳遞方案。當我們在我們的pom檔案中增加對某個starter的依賴時,該starter的依賴也會自動的傳遞性被依賴進來。而且,很多starter也依賴了其他的starter。例如web starter就依賴了tomcat-starter,並且大多數starter基本都依賴了spring-boot-starter。

Spring自動配置

Spring Boot會根據類路徑中的jar包、類,為jar包裡的類自動配置,這樣可以極大的減少配置的數量。簡單點說就是它會根據定義在classpath下的類,自動的給你生成一些Bean,並載入到Spring的Context中。自動配置充分的利用了spring 4.0的條件化配置特性,能夠自動配置特定的Spring bean,用來啟動某項特性。

條件化配置

Spring 4本身提供了很多已有的條件供直接使用,如:

@ConditionalOnBean
@ConditionalOnClass
@ConditionalOnExpression
@ConditionalOnMissingBean
@ConditionalOnMissingClass
@ConditionalOnNotWebApplication
複製程式碼

Spring Boot應用的啟動入口

自動配置充分的利用了spring4.0的條件化配置特性,那麼,SpringBoot是如何實現自動配置的?Spring4中的條件化配置又是怎麼運用到SpringBoot中的呢?這要從SpringBoot的啟動類說起。SpringBoot應用通常有一個名為*Application的入口類,入口類中有一個main方法,這個方法其實就是一個標準的Java應用的入口方法。

一般在main方法中使用SpringApplication.run()來啟動整個應用。值得注意的是,這個入口類要使用@SpringBootApplication註解宣告。@SpringBootApplication是SpringBoot的核心註解,他是一個組合註解。

@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 {
   // 略
}
複製程式碼

@SpringBootApplication是一個組合註解,它主要包含@SpringBootConfiguration、@EnableAutoConfiguration等幾個註解。也就是說可以直接在啟動類中使用這些註解來代替@SpringBootApplication註解。關於SpringBoot中的Spring自動化配置主要是@EnableAutoConfiguration的功勞。該註解可以讓SpringBoot根據類路徑中的jar包依賴為當前專案進行自動配置。

至此,我們知道,SpringBoot的自動化配置主要是通過@EnableAutoConfiguration來實現的,因為我們在程式的啟動入口使用了@SpringBootApplication註解,而該註解中組合了@EnableAutoConfiguration註解。所以,在啟動類上使用@EnableAutoConfiguration註解,就會開啟自動配置。

那麼,本著刨根問底的原則,當然要知道@EnableAutoConfiguration又是如何實現自動化配置的,因為目前為止,我們還沒有發現Spring 4中條件化配置的影子。

EnableAutoConfiguration

其實Spring框架本身也提供了幾個名字為@Enable開頭的Annotation定義。比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和這些註解其實是一脈相承的。

@EnableScheduling是通過@Import將Spring排程框架相關的bean定義都載入到IoC容器。

@EnableMBeanExport是通過@Import將JMX相關的bean定義載入到IoC容器。

@EnableAutoConfiguration也是藉助@Import的幫助,將所有符合自動配置條件的bean定義載入到IoC容器。
複製程式碼

下面是EnableAutoConfiguration註解的原始碼:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    //略
}
複製程式碼

觀察@EnableAutoConfiguration可以發現,這裡Import了@EnableAutoConfigurationImportSelector,這就是Spring Boot自動化配置的“始作俑者”。

至此,我們知道,至此,我們知道,由於我們在SpringBoot的啟動類上使用了@SpringBootApplication註解,而該註解組合了@EnableAutoConfiguration註解,@EnableAutoConfiguration是自動化配置的“始作俑者”,而@EnableAutoConfiguration中Import了@EnableAutoConfigurationImportSelector註解,該註解的內部實現已經很接近我們要找的“真相”了。 EnableAutoConfigurationImportSelector的原始碼在這裡就不貼了,感興趣的可以直接去看一下,其實實現也比較簡單,主要就是使用Spring4提供的的SpringFactoriesLoader工具類。通過SpringFactoriesLoader.loadFactoryNames()讀取了ClassPath下面的META-INF/spring.factories檔案。

EnableAutoConfigurationImportSelector通過讀取spring.factories中的key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的值。如spring-boot-autoconfigure-1.5.1.RELEASE.jar中的spring.factories檔案包含以下內容:

# 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.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
......
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
複製程式碼

上面的EnableAutoConfiguration配置了多個類,這些都是SpringBoot中的自動配置相關類;在啟動過程中會解析對應類配置資訊。每個Configuation都定義了相關bean的例項化配置。都說明了哪些bean可以被自動配置,什麼條件下可以自動配置,並把這些bean例項化出來。

如果我們新定義了一個starter的話,也要在該starter的jar包中提供 spring.factories檔案,並且為其配置org.springframework.boot.autoconfigure.EnableAutoConfiguration對應的配置類
複製程式碼

總結

通過Spring 4的條件配置決定哪些bean可以被配置,將這些條件定義成具體的Configuation,然後將這些Configuation配置到spring.factories檔案中,作為key: org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,這時候,容器在啟動的時候,由於使用了EnableAutoConfiguration註解,該註解Import的EnableAutoConfigurationImportSelector會去掃描classpath下的所有spring.factories檔案,然後進行bean的自動化配置。

所以,如果我們想要自定義一個starter的話,可以通過以上方式將自定義的starter中的bean自動化配置到Spring的上下文中,從而避免大量的配置

相關文章