在Spring Boot的源码中,配置文件的加载是在应用程序启动的早期阶段进行的。具体来说,配置文件加载的主要步骤发生在SpringApplication
类的run()
方法中的prepareEnvironment
方法中,真正读取我们的配置文件还是PropertySourceLoader。
本篇博客适合准备看源码,和想了解配置文件加载大体逻辑的同学。
本篇文章主要粘贴了加载配置文件的主要处理逻辑的源码,方便各位同学直接定位关键代码,辅助大家了解配置文件被处理的过程。
prepareEnvironment()
方法: 应用程序的入口点是SpringApplication
类的run()
,加载配置的方法入口run()
中调用的prepareEnvironment()
方法。初始化environment
对象用于后续存储环境信息,以及后续处理逻辑的入口都在这个方法。
ApplicationEnvironmentPreparedEvent
事件: 发布环境准备事件,通过spring事件发布机制去处理环境对象。关键代码 listeners.environmentPrepared(bootstrapContext, environment);
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
//本行代码是解析配置的核心代码
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
configureAdditionalProfiles(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
这行代码我们继续debug的话会发现,核心逻辑就是发布了一个ApplicationEnvironmentPreparedEvent
事件,通过debug可以发现有以下7个监听器对该事件做了监听。虽然有7个监听器,从类名上看我肯定是重点关注EnvironmentPostPorcessorApplicationListener
EnvironmentPostProcessor
接口:我们继续跟踪EnvironmentPostPorcessorApplicationListener
监听器的主要处理逻辑会发现,该监听器的逻辑主要是调用用EnvironmentPostProcessor
接口。直接上代码 EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
SpringApplication application = event.getSpringApplication();
for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(event.getBootstrapContext())) {
postProcessor.postProcessEnvironment(environment, application);
}
}
可以看到上面代码主要就是遍历EnvironmentPostProcessor接口并执行postProcessEnvironment方法,这个地方会遍历哪些接口,大家就自行打断点吧,关键的处理器为ConfigDataEnvironmentPostProcessor
这个接口postProcessEnvironment方法实现比较复杂,核心逻辑都在里面,分析到里面的方法我已经不行了。
这个地方所遍历接口,也是springboot通过其SPI机制,在初始化SpringApplication时set进去的
load()
方法:通过我们不断的debug postProcessEnvironment
方法,好像找到加载配置文件的主线了,load方法一看名字就是我们重点关注的对象!!!
下面是postProcessEnvironment到load的调用栈信息:
看一下load方法吧(下面代码有注释哦!):
public ConfigData load(ConfigDataLoaderContext context, StandardConfigDataResource resource)
throws IOException, ConfigDataNotFoundException {
if (resource.isEmptyDirectory()) {
return ConfigData.EMPTY;
}
ConfigDataResourceNotFoundException.throwIfDoesNotExist(resource, resource.getResource());
StandardConfigDataReference reference = resource.getReference();
Resource originTrackedResource = OriginTrackedResource.of(resource.getResource(),
Origin.from(reference.getConfigDataLocation()));
String name = String.format("Config resource '%s' via location '%s'", resource,
reference.getConfigDataLocation());
//获取properties,yml加载器,加载对应的资源生成propertySources,封装成ConfigData
List<PropertySource<?>> propertySources = reference.getPropertySourceLoader().load(name, originTrackedResource);
return new ConfigData(propertySources);
}
关键代码就暂时分析到这儿,当前中间还有很多的逻辑,目前能力有限暂时到这儿,后续也会对该篇博客持续更新!!!!
发布ApplicationEnvironmentPreparedEvent
事件进行一系列的处理,EnvironmentPostPorcessorApplicationListener
监听处理器,调用EnvironmentPostProcessor
接口处理环境加载配置,关键的接口实现是ConfigDataEnvironmentPostProcessor
类去处理,最后是读取我们本地资源,根据不同的配置文件找到对应的PropertySourceLoader
去加载我们
的properties,yaml 得到PropertySource,然后最后经过层层的封装,最后还是会放到environment中
问题遗留:配置文件优先级、远程配置如何加载的源码体现,后面再补充