为什么我要写spring.factories文件?
发布日期:2021-05-09 04:56:27 浏览次数:22 分类:博客文章

本文共 4338 字,大约阅读时间需要 14 分钟。

在阅读spring-boot相关源码时,常常见到spring.factories文件,里面写了自动配置(AutoConfiguration)相关的类名,因此产生了一个疑问:“明明自动配置的类已经打上了@Configuration的注解,为什么还要写spring.factories文件?”

这个话题需要从@SpringBootApplication注解开始说起。

查看@SpringBootApplication源码,我们能看到继承的以下注解:

@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容器中。

看到这里也许会有个疑问,在spring-boot项目中pom文件里面添加的依赖中的bean(spring-boot项目外的bean)是如何注册到spring-boot项目的spring容器中的呢?

这就需要讨论@EnableAutoConfiguration的作用。查看@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.class做了什么呢?通过其源码可以看出关键的部分为,

@Overridepublic 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),查看其源码发现,

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,        AnnotationMetadata annotationMetadata) {    if (!isEnabled(annotationMetadata)) {        return EMPTY_ENTRY;    }    AnnotationAttributes attributes = getAttributes(annotationMetadata);    List
configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set
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方法的源码,

protected List
getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List
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 Configurationorg.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类名。

————————————————
版权声明:本文为CSDN博主「SkyeBeFreeman」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/SkyeBeFreeman/article/details/96291283

上一篇:@InitBinder的作用
下一篇:spring注解之@Import注解的三种使用方式

发表评论

最新留言

感谢大佬
[***.8.128.20]2025年04月03日 03时38分30秒