在阅读spring-boot相关源码时,经常见到spring.factories文件,里面写了自动配置(AutoConfiguration)相关的类名,所以产生了一个疑问:“明明自动配置的类已经打上了@Configuration的注解,为何还要写spring.factories文件?”spring
这个话题须要从@SpringBootApplication注解开始提及。ide
查看@SpringBootApplication源码,咱们能看到继承的如下注解:spring-boot
@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 { …… }
其中比较重要的是@EnableAutoConfiguration和@ComponentScan两个注解。@ComponentScan注解的做用是扫描@SpringBootApplication所在的Application类(即spring-boot项目的入口类)所在的包(basepackage)下全部的@component注解(或拓展了@component的注解)标记的bean,并注册到spring容器中。this
看到这里也许会有个疑问,在spring-boot项目中pom文件里面添加的依赖中的bean(spring-boot项目外的bean)是如何注册到spring-boot项目的spring容器中的呢?spa
这就须要讨论@EnableAutoConfiguration的做用。查看@EnableAutoConfiguration源码,.net
@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.class
作了什么呢?经过其源码能够看出关键的部分为,code
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
其中,getAutoConfigurationEntry
方法获取了spring-boot项目中须要自动配置的项(bean),查看其源码发现,component
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, 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 = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
其中最重要的部分为getCandidateConfigurations
方法,它获取了全部可能参与到项目的候选配置bean,与之对应的,getExclusions
获取了全部不须要加载的配置bean。进一步查看getCandidateConfigurations
方法的源码,blog
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; }
这个方法的具体实现为,读取spring-boot项目的classpath下META-INF/spring.factories的内容,这个文件经常以K/V的形式存储数据,例如:继承
# Auto Configuration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.HelloAutoConfiguration,\ ……
getCandidateConfigurations方法获取须要自动配置的类,除去上面讲到的须要排除(exclude)的配置类,其余类将会注册到spring-boot项目的spring容器中。
看到这里,想必已经了解@EnableAutoConfiguration注解的工做原理,回到最初的话题,“为何要写spring.factories文件?”
结合前面提出的疑问——“在spring-boot项目中pom文件里面添加的依赖中的bean是如何注册到spring-boot项目的spring容器中的呢?”,不可贵出spring.factories文件是帮助spring-boot项目包之外的bean(即在pom文件中添加依赖中的bean)注册到spring-boot项目的spring容器的结论。因为@ComponentScan注解只能扫描spring-boot项目包内的bean并注册到spring容器中,所以须要@EnableAutoConfiguration注解来注册项目包外的bean。而spring.factories文件,则是用来记录项目包外须要注册的bean类名。原文连接:https://blog.csdn.net/SkyeBeFreeman/article/details/96291283