SpringBoot原理之自動配置機制詳解
前言
在當下的java生態裡,SpringBoot已經成為事實上的開發標準,絕大多數人現在都是面向SpringBoot編程。SpringBoot是對Spring的進一步封裝,整合瞭分佈式系統上下遊所需的各種類庫和組件,並且實現瞭開箱即用,而這一切的底層基礎就是SpringBoot的自動配置機制。
Spring配置類
Spring引入配置類是為瞭:1)替換冗長繁瑣的配置文件,2)提供更靈活的bean定義方式。使用@Configuration註解去標記一個配置類,通過其中含有@Bean註解的方法去創建一個bean,如下代碼
@Configuration public class HelloAutoConfiguration { @Bean HelloService helloService() { return new HelloService; } }
即為一個簡單的配置類,並且定義瞭一個HelloService的bean。在此之上,Spring還提供瞭一套條件加載機制,可以去動態控制一個配置類是否被加載。通過實現org.springframework.context.annotation.Condition接口,開發者就可以自己控制配置類的加載條件,滿足很多復雜的場景
SpringBoot自動配置
介紹完瞭Spring的配置類,我們來看看SpringBoot是怎麼利用這套機制去實現自動配置的。
自動配置的概念
首先,什麼是自動配置?我們看一下SpringBoot對於自動配置類的定義:
Auto-configuration classes are regular Spring @Configuration beans. They are located using the SpringFactoriesLoader mechanism (keyed against this class). Generally auto-configuration beans are @Conditional beans (most often using @ConditionalOnClass and @ConditionalOnMissingBeanannotations).
自動配置類就是一個普通的@Configuration配置類,通常會帶有一些@Conditional條件註解,並且使用SpringFactoriesLoader機制去定位加載它們(並非都是如此,還有其他一些Spring固有的加載方式,比如通過@ComponentScan包掃描或者顯式@Import方式都可以讓它們被發現)。
自動配置的運行機制
加載方式
自動配置機制的啟用是通過@EnableAutoConfiguration註解去控制的,因此需要在SpringBoot工程的入口類上啟用該註解,但是通常,我們一般使用@SpringBootApplication來代替,後者是一個註解的合集,包含瞭一些必要的默認配置,其中就有@EnableAutoConfiguration註解,其類的註釋上是這麼描述的:
Indicates a Configuration class that declares one or more @Bean methods and also triggers auto-configuration and component scanning. This is a convenience annotation that is equivalent to declaring @Configuration, @EnableAutoConfiguration and @ComponentScan.
它本身既標識一個配置類,同時也開啟瞭自動配置和組件掃描。
回到@EnableAutoConfiguration註解上,我們看一下該註解的定義
@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 {}; }
其中@Import(AutoConfigurationImportSelector.class)是功能生效的關鍵,該註解導入瞭AutoConfigurationImportSelector組件到Spring環境中,開啟自動配置類的掃描加載工作,該類實現瞭接口org.springframework.context.annotation.ImportSelector
public interface ImportSelector { /** * Select and return the names of which class(es) should be imported based on * the {@link AnnotationMetadata} of the importing @{@link Configuration} class. * @return the class names, or an empty array if none */ String[] selectImports(AnnotationMetadata importingClassMetadata); ....其他省略 }
其中selectImports方法會在Spring啟動時被調用,用於返回所有的自動配置類,調用入口在org.springframework.context.annotation.ConfigurationClassParser類中,該類是Spring專門用來加載處理所有@Configuration配置類的,具體的加載細節,限於篇幅問題,就不在本文中展開說明瞭,讀者們可自行去閱讀源碼,本人也許會在後續再另開一篇詳細說明。接著說selectImports方法,我們來看一下自動配置類的加載過程,AutoConfigurationImportSelector對於該方法的具體實現為
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
isEnabled方法是一個開關,用於控制是否啟用自動配置,邏輯很簡單,略過不提,往下看,關鍵邏輯在getAutoConfigurationEntry方法中,跟下去
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
很容易看到加載邏輯在getCandidateConfigurations方法中,後續代碼是去重和過濾的過程,再往下看
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; }
這個方法就很簡單明顯瞭,直接調用SpringFactoriesLoader去加載對應的內容,接下來我們再聊聊SpringFactoriesLoader機制是怎麼回事。
SpringFactoriesLoader機制
SpringFactoriesLoader直譯過來就是工廠加載機制,是Spring仿照Java的SPI機制實現的一套類加載機制,通過讀取模塊內的META-INF/spring.factories文件來加載類,該文件為Properties格式,其中key部分是一個Class全限定名稱,可以是一個接口、抽象類或者註解等,而value部分是一個支持逗號分割的實現類列表,比如
而SpringFactoriesLoader就是Spring提供的一個用於讀取解析META-INF/spring.factories文件的工具類,通過傳入一個Class類型加載其對應的實現類列表。
SpringFactoriesLoader如何應用在自動配置中
介紹完瞭SpringFactoriesLoader,我們來研究一下SpringBoot的自動配置機制中是怎麼使用它的,回到上面的getCandidateConfigurations方法中,我們看一下這一行
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
其中第一個參數是key對應Class類型,第二個參數是用哪個ClassLoader去加載配置文件,我們看一下getSpringFactoriesLoaderFactoryClass這個方法返回的具體Class是什麼
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
很簡單,直接返回@EnableAutoConfiguration註解對應的class類型,那麼自動配置類在META-INF/spring.factories文件中的配置方式就顯而易見瞭,上面截圖中最前面的部分
# AutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\ org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\ org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\ org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\ org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration
就是對應的自動配置類瞭。這些被配置在此處的類都會被作為自動配置類加載到Spring中,然後進行相應的處理,發揮出每個類的功能作用。
小結
SpringBoot的自動配置機制就簡單介紹到這裡瞭,相信看官們看完瞭之後也都有瞭一些瞭解,當然這篇文章裡還有很多相關內容沒有涉及到,包括自動配置類的條件加載方式、多個類之間的加載順序控制、排除和過濾機制,以及如何自定義自動配置類、重寫框架默認行為等等,這些內容筆者會在後續的文章中再進行詳細探討。
到此這篇關於SpringBoot原理之自動配置機制的文章就介紹到這瞭,更多相關SpringBoot自動配置機制內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Springboot @Configuration與自動配置詳解
- SpringBoot自動配置深入探究實現原理
- SpringBoot開發實戰之自動配置
- SpringBoot自動配置原理分析
- Java SpringBoot自動裝配原理詳解及源碼註釋