使用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)中获取值。
接口
注:若有错误,欢迎指出。