概述 前面我们简介了spring boot的自动配置机制,现在我们来探讨下spring boot是如何解决这么多繁荣复杂的自动配置类之间的依赖顺序的。
sort
在上一篇《Spring @AutoConfiguration源码详解》中,
EnableAutoConfigurationImportSelector中使用了自动配置类的排序
private
List<String> sort(List<String> configurations)
throws
IOException {
configurations =
new
AutoConfigurationSorter(getMetadataReaderFactory())
.getInPriorityOrder(configurations);
return
configurations;
}
MetadataReaderFactory 我们看到排序的函数用到了MetadataReaderFactory,它的作用生成对应类的MetadataReader 来获取标注的注解等元数据。
public interface
MetadataReaderFactory {
//通过类名获取MetadataReader
MetadataReader getMetadataReader(String className)
throws
IOException;
//通过resource获取MetadataReader,resource包含了.class file路径
MetadataReader getMetadataReader(Resource resource)
throws
IOException;
}
private
MetadataReaderFactory getMetadataReaderFactory() {
try
{
//默认从容器中获取元数据工厂
return
getBeanFactory().getBean(
SharedMetadataReaderFactoryContextInitializer.
BEAN_NAME
,
MetadataReaderFactory.
class
);
}
catch
(NoSuchBeanDefinitionException ex) {
//没有则创建缓存元数据工厂,可配置缓存大小,默认256
return new
CachingMetadataReaderFactory(
this
.
resourceLoader
);
}
}
AutoConfigurationSorter 在spring boot中提供了工具类AutoConfigurationSorter,来对自动配置类进行依赖处理。我们来看看源码:
class
AutoConfigurationSorter {
//…
public
List<String> getInPriorityOrder(Collection<String> classNames)
throws
IOException {
//自动配置类元数据缓存
final
AutoConfigurationClasses classes =
new
AutoConfigurationClasses(
this
.
metadataReaderFactory
, classNames);
List<String> orderedClassNames =
new
ArrayList<String>(classNames);
// 初始化按照字母排序
Collections.
sort
(orderedClassNames);
// 根据order排序
Collections.
sort
(orderedClassNames,
new
Comparator<String>() {
@Override
public int
compare(String o1, String o2) {
int
i1 =
classes
.get(o1).getOrder();
int
i2 =
classes
.get(o2).getOrder();
return
(i1 < i2) ? –
1
: (i1 > i2) ?
1
:
0
;
}
});
// 根据 @AutoConfigureBefore @AutoConfigureAfter 排序
orderedClassNames = sortByAnnotation(classes, orderedClassNames);
return
orderedClassNames;
}
…
} 我们看到三次排序逻辑如下: 1、按照类名字典排序 2、按照order排序 3、按照@AutoConfigureBefore @AutoConfigureAfter 依赖排序
前面两个排序比较简单,我们来看一下最有一个排序是怎么做的。
private
List<String> sortByAnnotation(AutoConfigurationClasses classes,
List<String> classNames) {
//待排序的有序列表(已经按照字典和order进行排序)
List<String> toSort =
new
ArrayList<String>(classNames);
//已经排序的有序列表
Set<String> sorted =
new
LinkedHashSet<String>();
//处理中的有序列表,类似中间缓存队列
Set<String> processing =
new
LinkedHashSet<String>();
while
(!toSort.isEmpty()) {
//执行排序
doSortByAfterAnnotation(classes, toSort, sorted, processing,
null
);
}
return new
ArrayList<String>(sorted);
}
//真正排序的方法,是这个递归函数
private void
doSortByAfterAnnotation(AutoConfigurationClasses classes,
List<String> toSort, Set<String> sorted, Set<String> processing,
String current) {
if
(current ==
null
) {
//当前为空,则从带排序列表中取第一个
current = toSort.remove(
0
);
}
//放到处理中
processing.add(current);
//获取所有需要在current之前执行的自动配置,即标注了@
AutoConfigureAfter
for
(String after : classes.getClassesRequestedAfter(current)) {
//循环依赖判断断言
Assert.
state
(!processing.contains(after),
“AutoConfigure cycle detected between ”
+ current +
” and ”
+ after);
//未处理过,则处理当前自动配置类之前的依赖自动配置类
if
(!sorted.contains(after) && toSort.contains(after)) {
doSortByAfterAnnotation(classes, toSort, sorted, processing, after);
}
}
//移除处理中
processing.remove(current);
//添加到已处理
sorted.add(current);
}
排序后依次再交给bean处理器处理,就可以正确的初始化自动配置bean了。那么最终是谁来执行这个导入选择器的呢? 答案是ConfigurationClassPostProcessor里面的ConfigurationClassParser。