【Spring Boot 源码学习】走近 AutoConfigurationImportSelector

这篇具有很好参考价值的文章主要介绍了【Spring Boot 源码学习】走近 AutoConfigurationImportSelector。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

《Spring Boot 源码学习系列》

【Spring Boot 源码学习】走近 AutoConfigurationImportSelector,开发框架-Spring Boot,spring boot,源码学习,自动配置导入选择器,ImportSelector,自动加载功能

引言

上篇博文我们了解了 @EnableAutoConfiguration 注解,其中真正实现自动配置功能的核心实现者 AutoConfigurationImportSelector 还没有详细说明,本篇将从它的源码入手来重点介绍。

主要内容

在介绍 AutoConfigurationImportSelector 之前,有必要了解下它所实现的 ImportSelector 接口 ,如下所示:

1. ImportSelector 接口

在上篇博文中,我们介绍过 @Import 注解,它的许多功能其实是需要 ImportSelector 接口来实现,ImportSelector 接口决定可引入哪些 @Configuration

下面我们来看一下 ImportSelector 接口的源码【spring-context:5.3.25】:

/**
 * 实现了确定基于给定选择条件应该导入哪些 @Configuration 类的类型的接口,
 * 通常是一个或多个注解属性。
 * 
 * 一个 ImportSelector 可以实现以下任意一个 Aware 接口,并在调用 selectImports 
 * 方法之前调用其对应的方法:
 *    EnvironmentAware
 *    BeanFactoryAware
 *    BeanClassLoaderAware
 *    ResourceLoaderAware
 * 
 * 另外,该类也可以提供一个带有以下支持的参数类型的单个构造函数:
 *    Environment
 *    BeanFactory
 *    ClassLoader
 *    ResourceLoader
 * 
 * ImportSelector 实现通常与普通的 @Import 注解一样进行处理。
 * 然而,还可以推迟选择要导入的内容,直到所有 @Configuration 
 * 类都被处理完毕(详见 DeferredImportSelector)。
 *
 */
public interface ImportSelector {

	/**
	 * 根据导入的 @Configuration 类的 AnnotationMetadata(注解元数据),
	 * 选择并返回应该导入的类名称。
	 * 
	 * @return 返回类名的数组,如果没有则返回空数组。
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

	/**
	 * 返回一个用于从导入的候选类中排除类的断言函数,
	 * 该函数会递归地应用于通过此选择器的导入项找到的所有类。
	 * 
	 * 如果对于给定的完全限定类名,该断言函数返回 true,
	 * 则该类将不被视为被导入的配置类,从而跳过类文件加载和元数据检查。
	 * 
	 * @return 返回一个用于完全限定的候选类名的筛选断言函数,该函数适用于递归导入的配置类。
	 * 如果没有筛选断言函数,则返回 null。
	 * @since 5.2.4
	 */
	@Nullable
	default Predicate<String> getExclusionFilter() {
		return null;
	}

}

通过阅读上述源码,我们可以看到 ImportSelector 接口提供了一个参数为 AnnotationMetadata【它里面包含了被 @Import 注解的类的注解信息,即注解元数据】 的方法 selectImports ,并返回了一个字符串数组【可以根据具体实现决定返回哪些配置类的全限定名】。

源码注释里也提到了,如果我们实现了 ImportSelector 接口的同时又实现了以下的 4Aware 接口,那么 Spring 保证在调用 ImportSelector 之前会先调用 Aware 接口的方法。

这 4 个 Aware 接口分别是:

  • EnvironmentAware
  • BeanFactoryAware
  • BeanClassLoaderAware
  • ResourceLoaderAware

我们本篇要重点进行源码解析的 AutoConfigurationImportSelector 就实现了上述 4Aware 接口,部分源码如下所示:

// 其他导入语句省略
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.Ordered;

/**
 * DeferredImportSelector 用于处理自动配置的延迟导入选择器。
 * 如果需要自定义的 @EnableAutoConfiguration 变体,也可以通过继承这个类来实现。
 */
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	// 其他省略
}

从上面的 类定义中,我们可以看到 AutoConfigurationImportSelector 并没有直接实现 ImportSelector 接口,而是实现了 DeferredImportSelector 接口【它是 ImportSelector 的子接口 】。

2. DeferredImportSelector 接口

AutoConfigurationImportSelector 为啥不直接实现 ImportSelector 接口,而是实现了 DeferredImportSelector 接口呢?它们俩有什么区别呢?

在讲解清楚之前,我们先来看看 DeferredImportSelector 接口的源码【spring-context:5.3.25】:

/**
 * 一种在所有 @Configuration bean 处理完毕后运行的 ImportSelector 变体。
 * 这种类型的选择器在所选的导入项带有条件时特别有用。
 * 
 * 实现类可以扩展 org.springframework.core.Ordered 接口或使用 
 * org.springframework.core.annotation.Order 注解来指定与
 * 其他 DeferredImportSelectors 的优先级。
 * 
 * 实现类还可以提供一个导入组(import group),
 * 它可以在不同的选择器之间提供额外的排序和过滤逻辑。
 */
public interface DeferredImportSelector extends ImportSelector {

	/**
	 * 返回一个特定的导入组。
	 * 默认实现会在不需要分组的情况下返回 null。
	 * 
	 * @return 导入组的类,如果没有则返回 null。
	 * @since 5.0
	 */
	@Nullable
	default Class<? extends Group> getImportGroup() {
		return null;
	}


	/**
	 * 用于将来自不同导入选择器的结果进行分组的接口。
	 * 
	 * @since 5.0
	 */
	interface Group {

		/**
		 * 使用指定的 DeferredImportSelector 处理导入的 @Configuration 类的 AnnotationMetadata。
		 */
		void process(AnnotationMetadata metadata, DeferredImportSelector selector);

		/**
		 * 返回此组应该导入的类的条目
		 */
		Iterable<Entry> selectImports();


		/**
		 * 一个条目,包含导入的配置类的 AnnotationMetadata 和要导入的类名。
		 */
		class Entry {

			private final AnnotationMetadata metadata;

			private final String importClassName;

			public Entry(AnnotationMetadata metadata, String importClassName) {
				this.metadata = metadata;
				this.importClassName = importClassName;
			}

			/**
			 * 返回导入的配置类的 AnnotationMetadata【注解元数据】
			 */
			public AnnotationMetadata getMetadata() {
				return this.metadata;
			}

			/**
			 * 返回要导入的类的完全限定名称。
			 */
			public String getImportClassName() {
				return this.importClassName;
			}

			// 省略。。。
		}
	}

}

通过阅读上述源码,可以了解到之所以 AutoConfigurationImportSelector 没有直接实现 ImportSelector 接口,而是实现了 DeferredImportSelector 接口,是因为通过DeferredImportSelector 接口能够在处理自动配置时,拥有更高的灵活性和可定制性。

总结来讲,它们的区别主要是如下几个方面:

  • 延迟导入DeferredImportSelector 具有延迟导入的能力,可以在所有的 @Configuration 类都被处理完毕之后再进行选择和导入。这样可以在整个配置加载过程完成后再根据某些条件或规则来决定要导入哪些类,从而实现更加动态和灵活的自动配置机制。

  • 筛选导入DeferredImportSelector 提供了一个用于筛选候选类名的断言函数,可以根据一定的条件来排除某些类的导入。这样可以对自动配置的候选类进行进一步的过滤和控制,使得只有符合特定条件的类才会被真正导入。

  • 自定义扩展:通过实现 DeferredImportSelector 接口,开发人员可以更方便地扩展和定制自动配置逻辑。可以根据实际需求重写相应方法,实现自定义的自动配置规则和行为。

上述源码注释中,也说明了 DeferredImportSelector 的加载顺序可以通过 @Order 注解 或 实现 Ordered 接口来指定。它还可以提供一个导入组,实现在不同的选择器之间提供额外的排序和过滤逻辑,从而实现自定义 Configuration 的加载顺序。

3. AutoConfigurationImportSelector 功能概述

好了到这里,我们终于可以开始正式介绍 AutoConfigurationImportSelector 了。

下面我们通过如下的流程图,从整体上来了解 AutoConfigurationImportSelector 的核心功能及流程【其中省略了外部通过 @Import 注解调用该类的部分】:

【Spring Boot 源码学习】走近 AutoConfigurationImportSelector,开发框架-Spring Boot,spring boot,源码学习,自动配置导入选择器,ImportSelector,自动加载功能

AutoConfigurationImportSelector 被 @Import 注解引入之后,它的 selectImports 方法会被调用并执行其实现的自动装配逻辑。

下面我们来看看 selectImports 方法的源码,如下所示:

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		// 检查自动配置功能是否开启,默认为开启
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		// 封装将被引入的自动配置信息
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		// 返回符合条件的配置类的全限定名数组
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}
	
	/**
	 * 根据导入@Configuration类的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry。
	 * @param 配置类的注解元数据。
	 * @return 应该导入的自动配置。
	 */
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		// 从AnnotationMetadata返回适当的AnnotationAttributes。默认情况下,此方法将返回getAnnotationClass()的属性。
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		// 通过 SpringFactoriesLoader 类提供的方法加载类路径中META-INF目录下的
		// spring.factories文件中针对 EnableAutoConfiguration 的注解配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		// 对获得的注解配置类集合进行去重处理,防止多个项目引入同样的配置类
		configurations = removeDuplicates(configurations);
		// 获得注解中被 exclude 或 excludeName 所排除的类的集合
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		// 检查被排除类是否可实例化,是否被自动注册配置所使用,不符合条件则抛出异常
		checkExcludedClasses(configurations, exclusions);
		// 从自动配置类集合中去除被排除的类
		configurations.removeAll(exclusions);
		// 检查配置类的注解是否符合 spring.factories 文件中 AutoConfigurationImportFilter 指定的注解检查条件
		configurations = getConfigurationClassFilter().filter(configurations);
		// 将筛选完成的配置类和排除的配置类构建为事件类,并传入监听器。监听器的配置在于 spring.factories 文件中,通过 AutoConfigurationImportListener 指定
		fireAutoConfigurationImportEvents(configurations, exclusions);
		// 创建并返回一个条目,其中包含了筛选完成的配置类和排除的配置
		return new AutoConfigurationEntry(configurations, exclusions);
	}

总结

通过阅读上述源码,对照相关的流程图,我们从整体上了解了 AutoConfigurationImportSelector 自动装配逻辑的核心功能及流程,由于篇幅有限,更加细化的功能及流程解析,笔者将在后续的博文中,带大家一起通过源码来一步步完成,敬请期待!!!文章来源地址https://www.toymoban.com/news/detail-650305.html

到了这里,关于【Spring Boot 源码学习】走近 AutoConfigurationImportSelector的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring Boot 源码学习】BootstrapRegistryInitializer 详解

    《Spring Boot 源码学习系列》 书接前文《初识 SpringApplication》,我们从 Spring Boot 的启动类 SpringApplication 上入手,了解了 SpringApplication 实例化过程。其中,有如下三块内容还未详细分析: 本篇博文就主要围绕 2.3 的内容展开,详细分析一下加载并初始化 BootstrapRegistryInitializer

    2024年02月04日
    浏览(35)
  • 【Spring Boot 源码学习】BootstrapRegistry 详解

    《Spring Boot 源码学习系列》 前面的博文《BootstrapRegistryInitializer 详解》,Huazie 带大家一起详细分析了 Spring Boot 启动时加载并初始化 BootstrapRegistryInitializer 及其相关的类的逻辑。其中有个 BootstrapRegistry 接口只是简单提及,本篇就详细分析一下 BootstrapRegistry 接口,这对于我们后

    2024年02月20日
    浏览(35)
  • 【Spring Boot 源码学习】初识 SpringApplication

    《Spring Boot 源码学习系列》 往期的博文, Huazie 围绕 Spring Boot 的核心功能,带大家从总整体上了解 Spring Boot 自动配置的原理以及自动配置核心组件的运作过程。这些内容大家需要重点关注,只有了解这些基础的组件和功能,我们在后续集成其他三方类库的 Starters 时,才能够

    2024年02月05日
    浏览(37)
  • 【Spring Boot 源码学习】OnWebApplicationCondition 详解

    《Spring Boot 源码学习系列》 上篇博文带大家从 Spring Boot 源码深入详解了 OnBeanCondition ,那本篇也同样从源码入手,带大家深入了解 OnWebApplicationCondition 的过滤匹配实现。 在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】: Spr

    2024年02月08日
    浏览(37)
  • 【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解

    Spring Boot 源码学习系列 前面的博文,我们从源码角度介绍了自动装配流程。虽然带大家从整体上有了清晰的认识,但是我们还不能熟练地运用。本篇就以 Spring Boot 内置的 http 编码功能为例,来带大家分析一下 HttpEncodingAutoConfiguration 的整个自动配置的过程。 在开始本篇的内容

    2024年02月08日
    浏览(35)
  • 【Spring Boot 源码学习】深入 FilteringSpringBootCondition

    Spring Boot 源码学习系列 前两篇博文笔者带大家从源码深入了解了 Spring Boot 的自动装配流程,其中自动配置过滤的实现由于篇幅限制,还未深入分析。 那么从本篇开始,Huazie 就带大家走近 AutoConfigurationImportFilter ,一起从源码解析 FilteringSpringBootCondition 、 OnBeanCondition 、 OnCl

    2024年02月09日
    浏览(38)
  • 【Spring Boot 源码学习】@Conditional 条件注解

    《Spring Boot 源码学习系列》 前面的博文,Huazie 带大家从 Spring Boot 源码深入了解了自动配置类的读取和筛选的过程,然后又详解了 OnClassCondition 、 OnBeanCondition 、 OnWebApplicationCondition 这三个自动配置过滤匹配子类实现。 在上述的博文中,我们其实已经初步涉及到了像 @Conditi

    2024年02月07日
    浏览(40)
  • 【Spring Boot 源码学习】BootstrapContext的实际使用场景

    《Spring Boot 源码学习系列》 上一篇博文《BootstrapRegistry 初始化器实现》, Huazie 向大家介绍了如何自定义 BootstrapRegistryInitializer 接口实现,并以此来执行自定义的初始化操作【如注册自定义的 Bean 、添加 BootstrapContext 关闭监听器】。其中涉及到了 BootstrapContext 的部分使用场景

    2024年03月11日
    浏览(43)
  • 【Spring Boot 源码学习】SpringApplication 的定制化介绍

    《Spring Boot 源码学习系列》 前面的博文, Huazie 带大家从 Spring Boot 的启动类 SpringApplication 上入手,了解了 SpringApplication 的实例化过程。这实例化构造过程中包含了各种初始化的操作,都是 Spring Boot 默认配置的。如果我们需要定制化配置, SpringApplication 也提供了相关的入口

    2024年01月25日
    浏览(33)
  • java版本企业电子招标采购系统源码Spring Cloud + Spring Boot +二次开发

      java版本企业电子招标采购系统源码Spring Cloud + Spring Boot +二次开发   一、立项管理 1、招标立项申请 功能点:招标类项目立项申请入口,用户可以保存为草稿,提交。 2、非招标立项申请 功能点:非招标立项申请入口、用户可以保存为草稿、提交。 3、采购立项列表 功能点

    2024年02月06日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包