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

简介: @EnableAutoConfiguration 加载元数据配置加载元数据配置主要是为后续操作提供数据支持。我们先来看加载相关源代码的具体实现,该功能的代码依旧日在 selectlmpots 方法内。@OverridepublicString[] selectImports (AnnotationMetadata annotationMetadata) {AutoConfigurat ionMetadata autoConf igurationMetadata = AutoConfigurationMetadataLoader. loadMetadata(this. bea
@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 的耗时。后续章节中我们会看到过滤自动配置的具体使用方法。


image.png

@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));
}


相关文章
|
8月前
uniapp 全局数据(globalData)的设置,获取,更改
uniapp 全局数据(globalData)的设置,获取,更改
772 0
|
10月前
|
Java Maven Spring
maven项目,动态读取外部配置文件
maven项目,动态读取外部配置文件
234 0
|
安全 JavaScript 前端开发
动态配置
动态配置
680 0
|
3月前
|
移动开发 前端开发 JavaScript
动态获取新增的数据+项目实例介绍
动态获取新增的数据+项目实例介绍
63 0
|
9月前
|
计算机视觉
VS2019如何添加已有的配置表(使得之前已经配置好的属性可以无需配置直接使用)
VS2019如何添加已有的配置表(使得之前已经配置好的属性可以无需配置直接使用)
117 0
|
JavaScript
js如何拷贝元数据后,更改数据不对元数据有影响
js如何拷贝元数据后,更改数据不对元数据有影响
一个简单的页面加载管理类(包含加载中,加载失败,数据为空,加载成功)(上)
在最近公布的比赛框架中,发现了页面加载管理类,觉得挺有用的,所以做个简单的笔记。
80 0
一个简单的页面加载管理类(包含加载中,加载失败,数据为空,加载成功)(上)
一个简单的页面加载管理类(包含加载中,加载失败,数据为空,加载成功)(下)
在最近公布的比赛框架中,发现了页面加载管理类,觉得挺有用的,所以做个简单的笔记。
84 0
一个简单的页面加载管理类(包含加载中,加载失败,数据为空,加载成功)(下)
|
Java 开发工具 Windows
五、实现自定义配置属性动态加载
在我们日常开发项目时,经常需要自定义一些配置属性用于我们项目的一些启动配置,这里我们就直接在application-dev配置文件中直接实现一下自定义配置属性的读取与使用,便于我们在dev和prod配置文件来回切换。
71 0
五、实现自定义配置属性动态加载