美文网首页Java
AutoConfiguration加载元数据和自动配置组件

AutoConfiguration加载元数据和自动配置组件

作者: 马小莫QAQ | 来源:发表于2020-10-12 15:29 被阅读0次

@EnableAutoConfiguration 加载元数据配置

加载元数据配置主要是为后续操作提供数据支持。

我们先来看加载相关源代码的具体实现,该功能的代码依旧日在 selectlmpots 方法内。

@Override

publicString[] selectImports (AnnotationMetadata annotationMetadata) {

AutoConfigurat ionMetadata autoConf igurationMetadata = AutoConfigurationMetadataLoader. loadMetadata(this. beanClassLoader);

}

加载元数据的配置用到了AutoConfigurationMetadataLoader类提供的loadMetaData方法,该方法会默认加载类路径下 META-INF/springautoconfigure-metadata.properties 内的配置。

final class AutoConfigurationMetadataLoader {

//默认加载元数据的路径protected static final String PATH ="META- INF/spring- autoconfigure - metadata.

properties";

//默认调用改方法,传入默认 PATHstatic AutoConfigurat ionMetadata loadMetadata(ClassLoader classLoader )returnloadMetadata(classLoader, PATH);

static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, Stringpath) {try//获取数据存储 FEnumeration 中Enumeration urls = (classLoader != null) ? classLoader . getResources(path)

: ClassLoader . getSys temResources(path);

Properties properties = new Properties();while(urls.hasMoreElements()) {

//遍历 Enumeration 中的 URL,加载其中的属性, 存储到 Properties 中properties . putAll(PropertiesLoaderUtils. loadProperties (new UrlResource(urls .nextElement())));}returnloadMetadata(properties);

} catch (IOException ex) {throw new IllegalArgumentException("Unable to load @ConditionalOnClas

; location ["+path+"]",ex);

//创建 AutoConfigurat ionMe tadata 的实现类 PropertiesAutoConf igurat ionMetadatstatic AutoConfigurationMetadata loadMetadata(Properties properties) {returnnew PropertiesAutoConfigurationMetadata(properties);

// AutoConfigurationMetadata 的内部实现类private static class PropertiesAutoConfigurationMetadata implements AutoCon-figurat ionMetadata {。。。}。。。}

在上面的代码中 AutoConfigurationMetadataLoader 调用 ladMetadaClassLoadar cassLoaden)方法,会获取默认变量 PATH 指定的文件,然后加载并存储于 Enumeration 数据结构中。随后从变量 PATH 指定的文件中获取其中配置的属性存诸 Poperties 内,最终调用在该类内部实现的 AutoConfigurationMetadata 的子类的构造方法。

spring-autoconfigure-metadata.properties 文件内的配置格式如下。

自动配置类的全限定名.注解名称=值

如果 spnaotningre-etadata properties 文件内有多个值,就用英文逗号分隔,例如:

org. springframework . boot . autoconfigure .data. jdbc . IdbcRepositoriesAutoConfiguration . ConditionalOnClass=org. springframework.data. jdbc . repos itory. config.JdbcConfigurat ion, org. springframework. jdbc . core . namedpar am .NamedParameterJdbcOperations

。。。

为什么要加载此元数据呢?加载元数据主要是为了后续过滤自动配置使用。Spring Boot 使用-Annlation 的处理器来收集自动加载的条件,这些条件可以在元数据文件中进行配置。SpingBoot 会将收集好的 C@Confguration 进行一 次过滤,进而剔除不满足条件的配置类。

在官方文档中已经明确指出,使用这种配置方式可以有效缩短 SpringBoot 的启动时间,减少@oniguraio 类的数量,从而减少初始化 ean 的耗时。后续章节中我们会看到过滤自动配置的具体使用方法。

@EnableAutoConfiguration 加载自动配置 组件

加载自动配置组件是自动配置的核心组件之一,这些自动配置组件在类路径中 METAINF 目录下的 Ssping fctories 文件中进行注册。Spring Boof 预置了-部分常用组件,如果我们需要创建自己的组件,可参考 SpringBoot 预置组件在自己的 Starters 中进行配置,在后面的章节中会专门对此进行讲解。

通过 Sping Core 提供的 Soingacaorestoaodar 类可以读取 spring. fctories 文件中注册的类。下面我们通过源代码来看一下如何在 AutoConfigurationlmportSelector 类中通过 getCateConfigurations 方法来读取 spring.factories 文件中注册的类。

protectedList getCandidateConfigurations(Annotat ionMetadata metadata,

AnnotationAttributes attr

ibutes){

List configurations = SpringFactoriesLoader .loadFactoryNames(

getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());

Assert. notEmpty (configurations ,"No auto configuration classes found in META-INF/spring.f

actories. If you

+ "areusinga custom packaging, make sure that fileisC

orrect.");

return configurations;

protected Class<?> getSpringF actoriesLoaderFactoryClass() {

return EnableAutoConfiguration.class;

}

getCandidateConfigurations 方 法 使 用 SpringFactoriesL oader 类 提 供 的loadFactoryNames 方法来读取 META-INF/spring.factories 中的配置。如果程序未读取到任何 配 置 内 容 , 会 抛 出 异 常 信 息 。 而 loadFactoryNames 方 法 的 第 一 个 参 数 为getSpringFactoriesL oaderFactoryClass 方法返回的 EnableAutoConfiguration.class,也就是说 loadFactoryNames 只会读取配置文件中针对自动配置的注册类。

SpringFactoriesLoader 类的 loadFactoryNames 方法相关代码如下。

public final class SpringFactoriesLoader {

//概类加载文件的路径, 可能存在多个

public static final String FACTORIES_RESOURCE LOCATION ="META- INF/spring. factories";

//加载所有的 META- INF/spring. factories.文件,封装成 Map, 并从中获取指定类名的列表

public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {String factoryClassName = factoryClass . getName();returnloadSpringFactories (classLoader) . getOrDefault(factoryClassName ,

Collections . emptylist());//加载所有的 META- INF/spring. factories 文件,封装成 Map, Key 为接口的全类名,Valu

e 为对应配置值的 ist 集合private static Map> loadSpringFactories (@Nullable ClassLoader classLoader) {MultiValueMap result = cache.get(classLoader);if(result != null) {

returnresult;

try {Enumeration urls = (classLoader != null ?classLoader . getResources(FACTORIES_RESOURCE_LO

CATION) :ClassLoader . getSystemResources (FACTORIES_RESOU

RCE_LOCATION));

result = new LinkedMultiValueMap<>();while(urls .hasMoreElements()) {

URL url = urls .nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils . loadProperties ( resource);for(Map.Entry entry : properties .entrySet()) {

String factoryClassName = ((String) entry . getKey()).trim();for(String factoryName : StringUtils . commaDelimitedL istTo-

StringArray((String) entry.getValue())) {result . add(factoryClassName, factoryName . trim());cache. put(classLoader, result);returnresult;

} catch (I0Exception ex)throw new IllegalArgumentException("Unable to load factories from location ["+

FACTORIES_RESOURCE__LOCATION +"]",e

x);}}。。。}

简单描述以上加载的过程就是: SpringFactoriesLoader 加载 器加载指定 ClassL oader 下面的所有 META-INF/spring.factories 文件,并将文件解析内容存于 Map<String,List<String>>内。然后,通过 loadFactoryNames 传递过来的 class 的名称从 Map 中获得该类的配置列表。

结 合 下 面 spring.factories 文 件 的 内 容 格 式 , 我 们 可 以 更 加 清 晰 地 了 解Map<String,List<String>>中都存储了什么。

# Auto Configure

org. springframework . boot . autoconfigure . EnableAutoConf iguration=\

org. springframework . boot . autoconfigure . admin. Spr ingApplicat ionAdminJmxAutoC

onfig :

uration, \

org. springframework . boot . autoconfigure . aop . AopAutoConfiguration, \

org . springframework . boot . autoconfigure . amqp . RabbitAutoConfiguration, \

org. springframework . boot. autoconfigure . batch . BatchAutoConfiguration,\

org. springfr amework . boot . autoconfigure . cache . CacheAutoConfiguration, \

org. springframework . boot . autoconfigure . cassandra . CassandraAutoConfiguratio

n,\

。。。

以上代码仅以 EnableAutoConfiguration 配置的部分内容为例,spring.factories 文件的基本格式为自动配置类的全限定名=值,与 2.3.5 节中介绍的元数据的格式很相似,只不过缺少了“,注解名称”部分,如果包含多个值,用英文逗号分隔。

我们继续以 EnableAutoConfiguration 的配置为例 Map<String,List<String>>内存储的对应数据就是key值为\/nliin/古org.springframework.boot.autoconfigure .EnableAutoConfiguration,Value 值为其等号后面以分号分割的各种 AutoConfiguration 类。

当然,spring.factories 文件内还有其他的配置,比如用于监听的 Listeners 和用于过滤的Filters 等。很显然,在加载自动配置组件时,此方法只用到了 EnableAutoConfiguration 对应的配置。

因为程序默认加载的是 ClassLoader 下面的所有 META-INF/spring.factories文件中的配置,所以难免在不同的 jar 包中出现重复的配置。我们可以在源代码中使用 Set 集合数据不可重复的特性进行去重操作。

protectedfinalList removeDuplicates(Listlist) {

returnnewArrayList<>(newLinkedHashSet<>(list));

}

本文给大家讲解的内容是AutoConfiguration加载元数据配置和加载自动配置组件

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

感谢大家的支持!

相关文章

网友评论

    本文标题:AutoConfiguration加载元数据和自动配置组件

    本文链接:https://www.haomeiwen.com/subject/cctppktx.html