Spring创建Bean源码 - 解析配置类: 延迟导入选择器DeferredImportSelector

news/2024/11/30 20:40:42/

简介

DeferredImportSelector延迟导入选择器是Spring提供的一个扩展导入器,该导入器是ImportSelector的一个变体,该导入器是在处理配置类上@Import注解的时候注册的,当所有{@code @Configuration}配置类解析完成后才会运行所有被注册的DeferredImportSelector
该导入器的主要作用是,委托Group接口导入一组配置类。Springboot 的AutoConfigurationImportSelector实现了该接口,用于自动装配类的获取。请查看《Springboot源码-自动装配(一):AutoConfigurationImportSelector》

DeferredImportSelector接口

DeferredImportSelector继承自ImportSelector,扩展了getImportGroup方法,getImportGroup方法返回同一个Group类的DeferredImportSelector会被分到同一个组中。当所选导入是{@code @Conditional}时,这种类型的选择器可能特别有用,可能就是不同的Condition对应不同的DeferredImportSelector实现。

/*** {@link ImportSelector} 的变体,在解析完所有 {@code @Configuration} bean后运行。* 当所选导入是{@code @Conditional}时,这种类型的选择器可能特别有用。** <p>实现还可以扩展 {@link org.springframework.core.Ordered} 接口* 或使用 {@link org.springframework.core.annotation.Order} 注解来指示相对于其他 {@link DeferredImportSelector DeferredImportSelectors} 的优先级。* * <p>Springboot {@link org.springframework.boot.autoconfigure.AutoConfigurationImportSelector}实现了该接口,用于自动装配类的获取*/
public interface DeferredImportSelector extends ImportSelector {/*** 对不同导入选择器的导入结果进行分组的接口。** @return DeferredImportSelector所属的Group对象。* @since 5.0*/@Nullabledefault Class<? extends Group> getImportGroup() {return null;}
}

Group接口

group接口主要用于对DeferredImportSelector进行分组,遍历Group对应的DeferredImportSelector对象集合,依次执行Group的process方法处理对应的逻辑。然后利用selectImports方法将process处理后的结果已Entry的形式返回回来。Springboot自动装配类AutoConfigurationImportSelector实现了该process接口,主要用于读取Springboot的自动装配类。以下是Springboot实现该接口的具体类和方法。请看《Springboot源码-自动装配(一):AutoConfigurationImportSelector》

/*** 对不同导入选择器的导入结果进行分组的接口。** 也就是说一个Group可以对应多个DeferredImportSelector,DeferredImportSelector的getImportGroup方法返回同一个Group类,则会将这些DeferredImportSelector对象分到同一个组中。** <p> Springboot@{@link org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup}实现了该接口* 用于获取所有的自动装配类*** @since 5.0*/
interface Group {/*** 根据标注了@Import注解的配置类的注解元数据来执行DeferredImportSelector进行配置类的导入*  * <p>* 1.Springboot自动装配类AutoConfigurationImportSelector实现了该process接口,主要用于读取Springboot的自动装配类。以下是Springboot实现该接口的具体类和方法** @see org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process* @param metadata 标注了@Import注解的配置类的注解元数据*/void process(AnnotationMetadata metadata, DeferredImportSelector selector);/*** 返回包含导入配置类的全限定名和该配置类的注解元数据的{@link Entry}集合*/Iterable<Entry> selectImports();/*** 包含导入配置类的全限定名和该配置类的注解元数据的{@link Entry}*/class Entry {//配置类的注解元数据private final AnnotationMetadata metadata;// 配置类的全限定名private final String importClassName;public Entry(AnnotationMetadata metadata, String importClassName) {this.metadata = metadata;this.importClassName = importClassName;}/*** Return the {@link AnnotationMetadata} of the importing* {@link Configuration} class.*/public AnnotationMetadata getMetadata() {return this.metadata;}/*** Return the fully qualified name of the class to import.*/public String getImportClassName() {return this.importClassName;}@Overridepublic boolean equals(@Nullable Object other) {if (this == other) {return true;}if (other == null || getClass() != other.getClass()) {return false;}Entry entry = (Entry) other;return (this.metadata.equals(entry.metadata) && this.importClassName.equals(entry.importClassName));}@Overridepublic int hashCode() {return (this.metadata.hashCode() * 31 + this.importClassName.hashCode());}@Overridepublic String toString() {return this.importClassName;}}
}

DeferredImportSelectorHandler处理器

  1. DeferredImportSelectorHandler利用handle方法收集所有的DeferredImportSelector封装成DeferredImportSelectorHolder放入到list集合中。
  2. DeferredImportSelectorHandler利用process方法获取所有的导入类。

代码详细逻辑如下:

  1. 利用handle收集所有的DeferredImportSelector封装成DeferredImportSelectorHolder放入到list集合中。
  2. 执行类的导入
    1. 创建DeferredImportSelectorGroupingHandler对象
    2. 遍历所有的DeferredImportSelector对象,依次调用DeferredImportSelectorGroupingHandler的register方法向DeferredImportSelectorGroupingHandler中保存Group与该Group下所有DeferredImportSelector映射关系
    3. 执行DeferredImportSelectorGroupingHandler的processGroupImports方法进行类的导入
private class DeferredImportSelectorHandler {@Nullableprivate List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();/*** {@link DeferredImportSelector}的注册阶段* 处理指定的{@link DeferredImportSelector}.* 如果deferredImportSelector等于null,则说明{@link DeferredImportSelector}正在被收集,注册器将会将{@link DeferredImportSelector}注册到当前对象的list中* 如果deferredImportSelector不等于null,如果{@link DeferredImportSelector}正在被处理,则{@link DeferredImportSelector}也会根据其{@link DeferredImportSelector.Group}立即进行处理。** @param configClass    Import注解标注的配置类* @param importSelector the selector to handle*/public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);if (this.deferredImportSelectors == null) {DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();handler.register(holder);handler.processGroupImports();} else {this.deferredImportSelectors.add(holder);}}/*** {@link DeferredImportSelector}的执行阶段阶段* 1.执行DeferredImportSelector的getImportSelector获取导入组Group* 2.实例化获取到的导入组Group* 3.执行导入组Group的getImports方法获取所有的导入的配置类* 4.调用{@link ConfigurationClassParser#processImports(ConfigurationClass, SourceClass, Collection, Predicate, boolean)}方法处理配置类*/public void process() {List<DeferredImportSelectorHolder> 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<>();}}
}

DeferredImportSelectorGroupingHandler处理器

DeferredImportSelectorGroupingHandler处理器主要用于接受GroupDeferredImportSelector的注册,然后将每一个Group与其对应的所有DeferredImportSelector的对应关系保存起来,然后调用processGroupImports方法遍历每一个Group,执行组内的所有DeferredImportSelector,来获取所有的导入类。获取到的导入类会再次通过ConfigurationClassParser#processImports方法进行处理。

private class DeferredImportSelectorGroupingHandler {private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();/*** 注册Group对象** @param deferredImport DeferredImportSelector对象的包装器对象*/public void register(DeferredImportSelectorHolder deferredImport) {//获取DeferredImportSelector对应的导入Group对象,Springboot的自动配置类的导入就是基于该接口进行注册的Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();//将Group对象放入当前对象的Map中,后续交由下边的processGroupImports方法进行配置类的处理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());}/*** 调用processImports方法处理Group对象返回的所有导入配置类*/public void processGroupImports() {for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {Predicate<String> exclusionFilter = grouping.getCandidateFilter();//获取所有的自动配置类,方式有://1.又Springboot实现,功能为加载所有的自动配置类grouping.getImports().forEach(entry -> {ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());try {//处理所有的导入配置类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);}});}}/*** 实例化Group对象** @param type Group的类* @return 实例化Group对象*/private Group createGroup(@Nullable Class<? extends Group> type) {Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class);return ParserStrategyUtils.instantiateClass(effectiveType, Group.class,ConfigurationClassParser.this.environment,ConfigurationClassParser.this.resourceLoader,ConfigurationClassParser.this.registry);}
}

DeferredImportSelector持有器

private static class DeferredImportSelectorHolder {private final ConfigurationClass configurationClass;private final DeferredImportSelector importSelector;public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {this.configurationClass = configClass;this.importSelector = selector;}public ConfigurationClass getConfigurationClass() {return this.configurationClass;}public DeferredImportSelector getImportSelector() {return this.importSelector;}
}

DeferredImportSelectorGrouping

遍历Group集合,然后执行每一个Group中的每一个DeferredImportSelector获取导入类。

private static class DeferredImportSelectorGrouping {private final DeferredImportSelector.Group group;private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();DeferredImportSelectorGrouping(Group group) {this.group = group;}public void add(DeferredImportSelectorHolder deferredImport) {this.deferredImports.add(deferredImport);}/*** <pre>* 1.实现1* @see org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process* 2.实现2* @see org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports** </pre>* <p>* <p>* Return the imports defined by the group.** @return each import with its associated configuration class*/public Iterable<Group.Entry> getImports() {for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {/** 功能实现1:加载Springboot自动配置类*/this.group.process(deferredImport.getConfigurationClass().getMetadata(),deferredImport.getImportSelector());}/** 功能实现1:对加载进来的Springboot自动配置类进行处理,包含过滤掉排除的自动配置类、对配置类进行排序*/return this.group.selectImports();}public Predicate<String> getCandidateFilter() {Predicate<String> mergedFilter = DEFAULT_EXCLUSION_FILTER;for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {Predicate<String> selectorFilter = deferredImport.getImportSelector().getExclusionFilter();if (selectorFilter != null) {mergedFilter = mergedFilter.or(selectorFilter);}}return mergedFilter;}
}

http://www.ppmy.cn/news/655263.html

相关文章

MATLAB求解摄氏温度

问题&#xff1a;用MATLAB编写一个函数&#xff0c;函数功能为要求你输入华氏温度&#xff0c;计算其相应的摄氏温度并输出。当你输入为空时&#xff0c;提示输入有误&#xff0c;程序结束。 function CF2C(F) a(tempreature in F is:); F input(a); if FC (F-32)*5/9;X[tem…

电商基本术语B2B C2C B2C C2B O2O F2C B2B2C

B2B--企业对企业:案例:阿里巴巴、慧聪网 C2C--个人对个人:案例:淘宝、易趣、瓜子二手车 B2C--企业对个人:案例:唯品会、乐蜂网 C2B--个人对企业:案例:海尔商城、 尚品宅配 O2O--线上到线下:案例:美团、饿了吗 F2C--工厂到个人:从厂商到消费者的电子商务模式 B2B2C -企业-…

C++实践之华氏温度转摄氏温度

#include<iostream> #include<cmath> #include<iomanip> using namespace std; int main(){cout<<"输入华氏温度"<<endl;double F;cin >> F;double F2C(double F);cout << setprecision(4) << F2C(F);system("…

docker安装elasticsearch、kibana详细教程

1. docker安装 7.4.2 docker pull elasticsearch:7.4.2 2. 查看elasticsearch镜像是否已安装 docker images 3. 安装 kibana docker pull kibana:7.4.2 4. 查看kibana镜像是否已安装 docker images 5…

浅谈如何编译COIN-OR的开源代码

转载自 http://hi.baidu.com/kaien_space/blog/item/420918134592880a5aaf53c9.html 浅谈如何编译COIN-OR的开源代码 2009-03-04 09:26 COIN-OR 是( COmputationalINfrastructure for Operations Research) 的简称。是国际知名的运筹和优化程序包代码开发组织。集结了当今运筹…

总之2022,我的研发、直播、软文触达13W+人的成果打包拿走,展望2023一起加油

导读 | 2022年勇哥算是正是进入写作圈&#xff0c;在小伙伴们的支持下&#xff0c;勇哥也是每日每夜的肝&#xff0c;真心和小伙伴们分享技术前沿路上的系列故事&#xff0c;大家相互鼓励与支持&#xff0c;勇哥也是收获满满&#xff01;现在勇哥通过这边文章整理一下本年度&am…

BFC、IFC、GFC、FFC

BFC、IFC、GFC、FFC CSS2.1中只有BFC和IFC, CSS3中才有GFC和FFC。 那么到底什么是BFC、IFC、GFC和FFC呢&#xff1f; What’s FC? 一定不是KFC&#xff0c;FC的全称是: Formatting Contexts&#xff0c;是W3CCSS2.1规范中的一个概念。它是页面中的一块渲染区域&#xff0c…

【F2C】hacker101 writeup(更新中)

Hacker101练习地址 目录 Petshop Proflag1 PostBookflag0flag get#flag1flag2flag3flag4flag5 一些参考&#xff1a; https://www.anquanke.com/post/id/180186#h2-1 https://github.com/testerting/hacker101-ctf https://zhuanlan.zhihu.com/p/61338756 Hacker101](https:…