@EnableAutoConfiguration和@ImportAutoConfiguration注解的区别
首先, 说明一下, 我是在研究SpringBoot测试相关内容, 在
@DataJpaTest
注解上发现的这个@ImportAutoConfiguration
注解, 本着不懂就学的态度, 顺便研究一下!
@EnableAutoConfiguration
注解大家都知道, 属于启动类注解@SpringBootApplication
中的注解
1. 先比较一下两个注解
两点不同
-
@EnableAutoConfiguration多了一个@AutoConfigurationPackage注解, 这个@AutoConfigurationPackage是用来存储自动扫描的包信息, 给后续的Jpa等扫包使用
-
@Import引入的类不同, 这是主要的一点, 我们着重来看一下
@Import注解的作用
@Import注解的作用是为了单独引入配置类, 可以是外部配置也可以是自定义的配置, 关于他的更多细节, 暂时先不展开了, 如果感兴趣, 欢迎评论区留言.
2. 重点研究一下这两个类
AutoConfigurationImportSelector类
selectImports方法
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 如果不开启自动配置, 返回空
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 从META-INF/spring.factories文件中获取自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
// 去除重复的自动配置类
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 排除手动设置的需要去除的配置类
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 利用OnClassCondition类对依赖的类进行校验
configurations = filter(configurations, autoConfigurationMetadata);
// 发送自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
再看ImportAutoConfigurationImportSelector
这个类继承自上面的AutoConfigurationImportSelector
, 那我们重点关注一下这个类重写的一些方法
getCandidateConfigurations方法
@Override
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> candidates = new ArrayList<>();
// 获取所有的@ImportAutoConfiguration注解
Map<Class<?>, List<Annotation>> annotations = getAnnotations(metadata);
// 重点关注一下 collectCandidateConfigurations方法
annotations.forEach((source, sourceAnnotations) -> collectCandidateConfigurations(
source, sourceAnnotations, candidates));
return candidates;
}
collectCandidateConfigurations方法
private void collectCandidateConfigurations(Class<?> source,
List<Annotation> annotations, List<String> candidates) {
for (Annotation annotation : annotations) {
// 跟进 getConfigurationsForAnnotation 方法
candidates.addAll(getConfigurationsForAnnotation(source, annotation));
}
}
getConfigurationsForAnnotation方法
private Collection<String> getConfigurationsForAnnotation(Class<?> source,
Annotation annotation) {
// 获取@ImportAutoConfiguration中的classes属性
String[] classes = (String[]) AnnotationUtils
.getAnnotationAttributes(annotation, true).get("classes");
// 如果classes不为空则返回
if (classes.length > 0) {
return Arrays.asList(classes);
}
// 否则获取底层类在META-INF/spring.factories文件中对应的配置类
return loadFactoryNames(source);
}
结合@DataJpaTest看一下
@ImportAutoConfiguration
注解执行上述ImportAutoConfigurationImportSelector
解析流程
-
获取所有的
@ImportAutoConfiguration
注解, 这里可不止是他自己啊, 还有一堆AutoConfiguration开头的注解, 随便选一个看一下TIPS:
这里也间接说明以AutoConfiguration开头的注解功能上都是通过
@ImportAutoConfiguration
实现的
- 但是所有的
@ImportAutoConfiguration中
的classes
属性都是空的, 这种情况下就会从META-INF/spring.factories
获取底层类为key的配置类(底层类指的就是@ImportAutoConfiguration
修饰的类), 试着随便找一个
经过上面的分析, 大家肯定已经大体对两个注解的处理流程有了一定的认识, 下面我们来总结一下! (如果大家觉得看完对自己有那么一丁点的帮助, 帮我点点赞吧, 感谢感谢)
总结一下
-
@EnableAutoConfiguration
是加载所有的自动配置类, 这其中包含了缓存, JPA等功能的自动配置类org.springframework.boot.autoconfigure.EnableAutoConfiguration
为key的自动配置类
-
而
@ImportAutoConfiguration
加载自定义属性classes中的配置类集合或者某一独立功能的自动配置类集合(如AutoConfigureCache
) -
因此
@ImportAutoConfiguration
的相比较@EnableAutoConfiguration
而言, 更加灵活, 并且实现了对自动配置的范围定制