使用springboot也有些時間,一直很好奇它如何作到自動配置的,因此查閱了相關資料而且學習了相關內容,才寫了這篇文章。java
①第一步咱們從它的啓動配置類(XxxApplication)收起,咱們進入到他的@SpringBootApplication註解。
spring
②咱們能夠看到以下代碼,因爲咱們須要找到致使它自動配置的,因此鎖定了@EnableAutoConfiguration註解,那麼就能夠進入這個註解。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 { @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 {}; }
③ 咱們看到了以下代碼,因爲這是一個接口,而它的實現類咱們又很差肯定,因此咱們只好從註解入手,因爲@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited等都是元註解,咱們能夠從@AutoConfigurationPackage,@Import({AutoConfigurationImportSelector.class})中找到咱們想要的,根據它的中文意思咱們能夠從@Import({AutoConfigurationImportSelector.class})(自動有選擇的導入配置)出發,畢竟不是全部的配置都會都如,而導入那些配置根據項目中使用了那些starter決定。
app
④點入第三步提到的註解,進入這個類根據方法名咱們能夠猜想是和這個方法相關,經過閱讀這個代碼,咱們能夠猜想是和getAutoConfigurationEntry這個方法有關,因此不妨點進去。學習
public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
⑤因爲咱們須要的配置Config,因此大體能夠判定是和這個代碼有關聯List
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { AnnotationAttributes attributes = this.getAttributes(annotationMetadata); List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); configurations = this.removeDuplicates(configurations); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); } }
⑥通過第五步,咱們能夠看到以下代碼code
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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; }
不妨看這部分代碼,List
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
看到這裏可能仍是會疑惑?爲啥就自動配置了,其實咱們這個方法(loadFactoryNames)是從一個配置文件中讀取內容,它的鍵是EnableAutoConfiguration,而這個配置文件是在如圖所示的文件中。blog
⑥打開上述文件,根據上一步的鍵找它的值,如圖就是springboot配置類,那麼項目啓動時是否是全部的配置都起做用嗎?不妨進入到某個配置類查看便可。如圖所示的@ConditionalOnMissingBean註解表示項目的容器是否有這個bean,若是沒有這個配置類就不會其做用,另外咱們只要在仔細看這個類首先進行了初始化,以後它會從配置文件(application.xml或者application.yml)中獲取值。
接口
注:若有錯誤,歡迎指出。