目录
一、DeferredImportSelector类结构和接口调用时机
二、DeferredImportSelectorHandler的process方法
1、DeferredImportSelectorGroupingHandler结构
2、DeferredImportSelectorGroupingHandler的register方法
3、DeferredImportSelectorGroupingHandler的processGroupImports方法
在分析DeferredImportSelector之前,根据名字Deferred(延迟的)ImportSelector。ImportSelector则是将selectImports返回的字符串数组,注册成为Bean,详细过程可以参见:Spring源码-ImportSelector实现分析。那么有几个问题:1)、怎么延迟的;2)、执行时机,或者在什莫时候被调用的;3)、返回后的字符串数组,怎么注册成Bean(或者Beandefinition)。
之前在分析Spring源码时,并没有分析DeferredImportSelector类型,其两个官方的实现类AutoConfigurationImportSelector和ImportAutoConfigurationImportSelector都是Spring Boot后新增的实现。
public interface DeferredImportSelector extends ImportSelector {
default Class extends Group> getImportGroup() {
return null;
}
interface Group {
void process(AnnotationMetadata metadata, DeferredImportSelector selector);
Iterable selectImports();
class Entry {
private final AnnotationMetadata metadata;
private final String importClassName;
public Entry(AnnotationMetadata metadata, String importClassName) {
this.metadata = metadata;
this.importClassName = importClassName;
}
}
}
}
DeferredImportSelector的回调时机发生在ConfigurationClassPostProcessor处理阶段,但是在处理DeferredImportSelector类型时并没有回调从顶层接口ImportSelector的selectImports(AnnotationMetadata importingClassMetadata)方法,则按道理AutoConfigurationImportSelector(自动装配)的该接口只需要写一个空方法即可。
执行该回调方法的先后顺序为 Group#process 和 Group#selectImports,回调时机为:
AbstractApplicationContext # refresh
AbstractApplicationContext # invokeBeanFactoryPostProcessors
PostProcessorRegistrationDelegate # invokeBeanFactoryPostProcessors
PostProcessorRegistrationDelegate # invokeBeanDefinitionRegistryPostProcessors
ConfigurationClassPostProcessor # postProcessBeanDefinitionRegistry
ConfigurationClassPostProcessor # processConfigBeanDefinitions
ConfigurationClassParser # parse
ConfigurationClassParser$DeferredImportSelectorHandler # process (下面都为代理对象处理)
ConfigurationClassParser$DeferredImportSelectorGroupingHandler # processGroupImports
ConfigurationClassParser$DeferredImportSelectorGrouping # getImports
之前在分析ConfigurationClassPostProcessor的处理过程的时候并没有注意到DeferredImportSelector类型的处理过程(详细可以参考:SpringIoc源码(十)- ApplicationContext(六)- refresh(ConfigurationClassPostProcessor上)),按照上面的调用trace继续分析,ConfigurationClassParser # parse方法,如下:
public void parse(Set configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}
其中for循环之前分析过了,会将可能存在的Bean进行注入,并且继续进行解析肯能的注解情况,比如:有一个@Component标注的类,上面还有@Import等情况。而deferredImportSelectorHandler.process()则是对DeferredImportSelector类型的处理。
看一下DeferredImportSelectorHandler deferredImportSelectorHandler的结构:
private List deferredImportSelectors = new ArrayList<>();
唯一的属性就是存放DeferredImportSelector类型的List,还有handle和process两个方法。而DeferredImportSelectorHolder的结构为:
private static class DeferredImportSelectorHolder {
// 注解所在类
private final ConfigurationClass configurationClass;
// DeferredImportSelector类型,比如:AutoConfigurationImportSelector
private final DeferredImportSelector importSelector;
}
DeferredImportSelector的两个官方实现都是Spring Boot的,看到上面的结构理解起来比较抽象。在启动Spring Boot项目时,默认只会注入一对值:
configurationClass为被@SpringBootApplication标注的启动类;
DeferredImportSelector为AutoConfigurationImportSelector类型。
继续deferredImportSelectorHandler.process()分析:
public void process() {
List deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
} finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
1)、创建DeferredImportSelectorGroupingHandler对象,对DeferredImportSelectorHolder类型List进行排序,然后遍历调用DeferredImportSelectorGroupingHandler的register方法,将DeferredImportSelectorHolder数据set到DeferredImportSelectorGroupingHandler内。
2)、调用hander的processGroupImports方法进行解析注册。
3)、finally,将容器置为空。
首先所有的解析过程交给DeferredImportSelectorGroupingHandler进行处理,先看看其内部结构。
private class DeferredImportSelectorGroupingHandler {
private final Map
有两个字段,通过register方法挨个进行register(相当于set方法)到上两个字段中, 最后统一调用processGroupImports方法进行处理。
1)、configurationClasses比较清楚,存放的是注解信息和标记注解的类(比如:当前为@SpringBootApplication锁在的类的注解信息被封装为StrandardAnnotationMetadata)。
2)、group中存储的key为DeferredImportSelector.Group或者DeferredImportSelectorHolder对象(因为是调用DeferredImportSelector的getImportGroup方法获取的,可能为null,所以key为Object类型)。value为DeferredImportSelectorGrouping类型,再看看其结构(还是比较清晰的,只是需要理解几层的关系):
private static class DeferredImportSelectorGrouping {
private final DeferredImportSelector.Group group;
private final List deferredImports = new ArrayList<>();
}
public void register(DeferredImportSelectorHolder deferredImport) {
Class extends Group> group = deferredImport.getImportSelector()
.getImportGroup();
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
grouping.add(deferredImport);
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
1)、调用DeferredImportSelector.Group的getImportGroup方法,获取返回的DeferredImportSelector.Group。
2)、grouping的put方法,Group为null则设置传入的DeferredImportSelectorHolder 本身。value为new的DeferredImportSelectorHolder 类型。
调用了createGroup方法,通过Class和反射创建对象;并且传入ConfigurationClassParser的environment、resourceLoader、registry对象,在反射创建完对象后对部分Aware方法进行了回调(BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware)。
没搞懂为什么要回调,因为Bean的生命周期本身就会进行回调。后面debugger发现,AutoConfigurationImportSelector本身实现了那几个接口,AutoConfigurationImportSelector.AutoConfigurationGroup也实现了那几个接口。知道当前的调用时机还没有进行getBean操作,不能执行生命周期方法(回调,设置BeanFactory等),但是执行DeferredImportSelector的process和selectImports方法时可能需要使用到上面四个AbstractApplicationContext级别的内置对象,则在此处回调赋值。
3)、上面先进行了put方法,返回了DeferredImportSelectorGrouping对象。再将DeferredImportSelectorHolder添加进去。
4)、为List
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(
entry.getMetadata());
try {
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);
} catch (BeanDefinitionStoreException ex) {
// 省略异常代码
}
});
}
}
主要有两步
1)、调用getImports方法获取Iterable
public Iterable getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
之前做了很多准备工作,当前需要通过调用DeferredImportSelector.Group的process和selectImports方法,返回Iterable
2)、遍历调用ConfigurationClassParser的processImports方法,将返回的Class类型进行解析并注册成Bean(如果该Class上有其他注解,也会递归进行解析注册完成,比如该类上还有@ComponentScan注解),可以参考Spring源码-ImportSelector实现分析。