一线大牛带你深入解析AutoConfiguration源码

愿天堂没有BUG

共 5973字,需浏览 12分钟

 · 2022-05-10



AutoConfiguration lmportSelector源码解析

@EnableAutoConfiguration 的关键功能是通过@Import 注解导入的 ImportSelector 来完成的从 源 代码得知@lmport(
AutoConfigurationlmportSelector.class) 是@EnableAutoConfiguration 注 解 的 组成部分 , 也是自动配置功能的核心实现者 。

@Ilmport(
AutoConfigurationlmportSele-ctor.class)又可以分为两部分:

@Ilmport 和对应的 ImportSelector。

本节重点讲解@lmport 的基本使用方法和ImportSelector 的实现类
AutoConfigurationlmportSelector。

@Import 注解

@lmport 注解位于 spring-context 项目内,主要提供导入配置类的功能。

为什么要专门讲解@lmport 的功能及使用呢?如果查看 Spring Boot 的源代码,我们会发现大量的 EnableXXX 类都使用了该注解。了 解@lmport 注解的基本使用方法,能够帮助我们更好地进行源代码的阅读和理解。

@lmport 的源码如下。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy. RUNTIME)
@Documented
public @interface Import {
Class[] value();
}

@lmport 的作用和 xml 配置中标签的作用一样,我们可以通过@lmport 弓|入@Configuration 注 解 的 类 , 也 可 以 导 入 实 现 了 ImportSelector 或
ImportBeanDefinitionRegistrar 的类,还可以通过@lmport 导入普通的 POJO(将其注册成Spring Bean,导入 POJO 需要 Spring 4.2 以上版本)。

关于@lmport 导入@Configuration 注解类和 POJO 的功能比较简单和常见,就不再展开介绍了。下面重点介绍 ImportSelector 接口的作用。

ImportSelector 接口

@Import 的许多功能都需要借助接口 ImportSelector 来实现,ImportSelector 决定可引入哪些@Configuration。ImportSelector 接口源码如下。

public interface ImportSelector
String[] selectImports (AnnotationMetadata importingClassMetadata)
;
}

ImportSelector 接口只提供了一个 参数为 AnnotationMetadata 的方法,返回的结果为一个字符串数组。其中参数 AnnotationMetadata 内包含了被@lmport 注解的类的注解信息。在selectlmports 方法内可根据具体实现决定返回哪些配置类的全限定名,将结果以字符串数组的形式返回。

如果实现了接口 ImportSelector 的类的同时又实现了以下 4 个 Aware 接口,那么 Spring 保证 在 调 用 ImportSelector 之 前 会 先 调 用 Aware 接 口 的 方 法 。这 4 个 接 口 为 :

EnvironmentAware 、 BeanFactoryAware 、 BeanClassLoaderAware 和 ResourceLoaderAware.


AutoConfigurationlmportSelector 的源代码中就实现了这 4 个接口,部分源代码及 Aware的全限定名代码如下。

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;
public class AutoConfigurat ionImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanF actoryAware, EnvironmentAware, Ordered
{
。。。}

在.上面的源代码中,
AutoConfigurationlmportSelector 并没有 直接实现 ImportSelector 接口,而是实现了它的子接口 DeferredIlmportSelector。

DeferredlmportSelector 接口与 ImportSelector 的区别是,前者会在所有的@Configuration类加载完成之后再加载返回的配置类,而 ImportSelector 是在加载完@Configuration 类之前先去加载返回的配置类。

DeferredlmportSelector 的加载顺序可以通过@Order 注解或实现 Ordered 接口来指定。同时,DeferredlmportSelector 提供了新的方法 getlmportGroup()来跨 DeferredlmportSelector实现自定义 Configuration 的加载顺序。


AutoConfigurationlmportSelector 功能概述

下面我们通过图 2-3 所示的流程图来从整体上了解
AutoConfigurationlmportSelector 的核心功能及流程,然后再对照代码看具体的功能实现。图 2-3 中省略了外部通过@Import 注解调用该类的部分。



AutoConfigurationlmportSelector 被@lmport 注解引入之后,它的 slectmports 方法会被调用并执行其实现的自动装配逻辑。读者朋友需注意,seletmports 方法几乎涵盖了组件自动装配的所有处理逻辑。


AhtonfiruriomoprSelelereleltiports 方法源代码如下:

@Override
public String[ ] selectImports (AnnotationMetadata annotationMetadata) {
//检查自动配置功能是否开肩,默认为开启
if (!isEnabled(annotat ionMetadata)) {
return NO_ IMPORTS;
//加戴自动配置的元信息,配置文件为类路径中 META-INF 目录下的
// spring-autoconfigure -metadata. properties 文件
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMe
tadataLoader
. loadMetadata(this . beanClassLoader);
//封装将被引入的自动配置信息
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry
autoConfigurationMetadata, annotationMetadata) ;
//返回符合条件的配置类的全限定名数组
return StringUtils. toStringArray(autoConfigurationEntry. getConfigurations
());
}
protected AutoConfigurationEntry getAutoConfigurat ionEntry(
AutoConfigurat ionMetadata autoConfi gurationMetadata,
Annotat ionMetadata annotationMetadata) {
if (!isEnabled( annotationMetadata)) {
return EMPTY_ ENTRY;
}
AnnotationAttributes attributes = getAttributes ( annotat ionMetadata);
//通过 SpringFactoriesLoader 类提供的方法加戴类路径中 META-INF 目录下的
// spring . factories 文件中针对 EnableAutoConfigurat ion 的往册配置类
List configurations = getCandidateConfigurations (annotationMetadata,
attributes);
//对获得的注册配置类集合进行去重处理,防止多个项目引入同样的配置类 configurations =
removeDuplicates( configurations);
//获得炷解中被 excLude.或 excLudeName 所排除的类的集合
Set exclusions = getExclusions ( annotationMetadata, attributes);
//检查被排除类是否可实例化,是否被自动注册配置所使用,不符合条件则抛出异常
checkExcludedClasses (configurations, exclusions);
//从自动配置类集合中去除被排除的类
configurations . removeAll(exclusions);
//检查配置类的注解是否符合 spring . factories 文件中 AutoConfigurat ionImportFilter.指定
的注解检查条件
configurations = filter( configurations, autoConfigurationMetadata);
//将筛选完成的配置类和排查的配置类构建为事件类, 并传入监听器。监听器的配置在
Fspring . factories 文件中,通过 AutoConf igurat ionImportL istener 指定
fireAutoConfigurationImportEvents( configurations, exclusions);
return new AutoConfigurat ionEntry(configurations, exclusions);
}

通过图 2-3 和上述代码,我们从整体层面了解了
AutoConfigurationlmportSelector 的概况及操作流程,后文将对这些流程进行细化拆分,并通过阅读源代码来分析 Sprng Boot 是如何实现自动加载功能的。

@Enable AutoConfiguration 自动配置开关

检查自动配置是否开启的代码位于
AutoConfiguratinmportSelector的selectmpots方法第一段中。如果开启自动配置功能,就继续执行后续操作;如果未开启,就返回空数组。代码如下。

@Override
public String[]
selectImports (AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotat ionMetadata)) {
return NO_ IMPORTS;
}
}
该方法主要使用 isEnabled 方法来判断自动配置是否开启,代码如下。
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector . class) {
return getEnvironment(). getProperty(
EnableAutoConfiguration. ENABLED_ _OVERRIDE_ PROPERTY, Boolean.class,
true);

}
return true;}

通过 isEnabled 方法可以看出,如果当前类为
AutoConfigurationlmportSelector 程序会从环境中获取 key 为 EnableAutoConfiguration.ENABL ED_ OVERRIDE PROPERTY 的配置,该常量的值为 spring.boot.enableautoconfiguration.如果获取不到该属性的配置,isEnabled默认为 true,也就是默认会使用自动配置。如果当前类为其他类,直接返回 true。

如果想覆盖或重置.ENABLED_ _OVERRIDE_ PROPERTY 的配置,可获取该常量的值,并在 aplication.properties 或 plcatin.ym|中针对此参数进行配置。以 application.properties配置关闭自动配置为例,代码如下。

spring.boot.enableautoconfiguration-false

本文给大家讲解的内容是AutoConfigurationlmportSelector功能概述和AutoConfiguration自动配置开关

  1. 下篇文章给大家讲解的是AutoConfiguration加载元数据配置和加载自动配置组件;

  2. 觉得文章不错的朋友可以转发此文关注小编;

  3. 感谢大家的支持!


本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。


浏览 18
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报