本系列是在重看源码分析过程中,对一些遗漏内容的补充,内容仅用于个人学习记录,写的会比较随性,难免有错漏,欢迎指正。
全集目录:Spring源码分析:全集整理
在 Spring 源码分析衍生篇七 :ConfigurationClassPostProcessor 上篇 中我们讲到了在ConfigurationClassPostProcessor 中 完成了对 ImportSelector 和 DeferredImportSelector 的解析。
其中对于 ImportSelector 的调用直接是调用 ImportSelector#selectImports 方法完成解析即可,但是对于 DeferredImportSelector的调用,就没有那么直接了。本文来解析 DeferredImportSelector 的调用过程。
DeferredImportSelector
是 ImportSelector
接口的子接口。
DeferredImportSelector
有两个特点:
ConfigurationClassParser#parse(java.util.Set)
方法中直到解析出来其他的候选配置类才会调用 this.deferredImportSelectorHandler.process();
来解析 DeferredImportSelector
this.deferredImportSelectorHandler.process();
中进行了排序调用。借 死磕源码系列【ImportSelector接口原理解析】的话:
DeferredImportSelector接口是ImportSelector接口的子接口,该接口会在所有的@Configuration配置类(不包括自动化配置类,即spring.factories文件中的配置类)处理完成后运行;当选择器和@Conditional条件注解一起使用时是特别有用的,此接口还可以和接口Ordered或者@Ordered一起使用,定义多个选择器的优先级
由于 DeferredImportSelector 具有后处理的特性,所以在刚开始扫描出来DeferredImportSelector 的时候并不能立即处理,需要将其保存起来,在最后再进行统一的处理。
在 ConfigurationClassParser#processImports 中对DeferredImportSelector 的处理如下:
// deferredImportSelectorHandler 为 org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorHandler
// 这一步实际上是将 configClass 和 selector 保存到了一个集合(deferredImportSelectors)中,集合(deferredImportSelectors)标记着待处理的selector
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
其具体实现如下:
// ConfigurationClassParser.DeferredImportSelectorHandler#handle
// deferredImportSelectors 保存待处理的 Selector
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
// configClass 是持有该@Import 注解的 配置类, importSelector 是引入的 DeferredImportSelector
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
// 将 DeferredImportSelector 和其引入的配置类保存起来。
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
// 如果deferredImportSelectors 为空,则重新注册
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
}
else {
// 将当前的 config 和 Selector 的持有者保存起来
this.deferredImportSelectors.add(holder);
}
}
在 ConfigurationClassParser#parse(java.util.Set
中最后一句处理了 DeferredImportSelector
this.deferredImportSelectorHandler.process();
其详细实现如下:
public void process() {
// 获取待处理的 DeferredImportSelectorHolder
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
// 排序
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
// 1. 根据不同的group 进行分组注册
deferredImports.forEach(handler::register);
// 2. 按照分组调用
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
这里有两步操作 :
public void register(DeferredImportSelectorHolder deferredImport) {
// 获取当前 DeferredImportSelector 的Group
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
// 将当前 DeferredImportSelector 添加到同一分组中的
grouping.add(deferredImport);
// 保存需要处理的配置类
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
这一步根据不同分组将分组中的 DeferredImportSelector 引入的类通过 entry.getImportClassName() 来包装后,调用 processImports 方法进行了新一轮解析。
public void processGroupImports() {
// 遍历每个分组
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
// 获取分组的过滤器
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
// 遍历分组中所有的 Entry (封装了需要引入的类的信息)
grouping.getImports().forEach(entry -> {
// 从 configurationClasses 集合中获取到对应的 ConfigurationClass 。其中保存
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
// 对 configurationClass 进行解析。这里的解析在 ConfigurationClassPostProcessor 文章已经有过解释。
// entry.getImportClassName() 获取到了引入的类
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configurationClass.getMetadata().getClassName() + "]", ex);
}
});
}
}
其中 grouping.getImports()
的实现如下
// org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#getImports
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
// 调用 DeferredImportSelector.Group#process
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
// 调用 DeferredImportSelector.Group#selectImports
return this.group.selectImports();
}
我们这里调用的是 DefaultDeferredImportSelectorGroup
private static class DefaultDeferredImportSelectorGroup implements Group {
private final List<Entry> imports = new ArrayList<>();
@Override
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
// 调用了ImportSelector#selectImports 方法
for (String importClassName : selector.selectImports(metadata)) {
this.imports.add(new Entry(metadata, importClassName));
}
}
@Override
public Iterable<Entry> selectImports() {
// 直接将 Imports 返回
return this.imports;
}
}
综上可以看到 DeferredImportSelector 的处理过程并非是直接 调用ImportSelector#selectImports方法。而是调用 DeferredImportSelector.Group#process 和 Group#selectImports 方法来完成引入功能。
以上:内容部分参考
https://mingyang.blog.csdn.net/article/details/108861935
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正