【springboot配置文件加载源码分析】

2024-01-03 19:23:00

在Spring Boot的源码中,配置文件的加载是在应用程序启动的早期阶段进行的。具体来说,配置文件加载的主要步骤发生在SpringApplication类的run()方法中的prepareEnvironment方法中,真正读取我们的配置文件还是PropertySourceLoader。

本篇博客适合准备看源码,和想了解配置文件加载大体逻辑的同学。
本篇文章主要粘贴了加载配置文件的主要处理逻辑的源码,方便各位同学直接定位关键代码,辅助大家了解配置文件被处理的过程。

以下是Spring Boot源码中加载配置文件的主要步骤:

  1. prepareEnvironment()方法: 应用程序的入口点是SpringApplication类的run(),加载配置的方法入口run()中调用的prepareEnvironment()方法。初始化environment对象用于后续存储环境信息,以及后续处理逻辑的入口都在这个方法。

  2. 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
    在这里插入图片描述

  3. 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进去的

  4. 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中

问题遗留:配置文件优先级、远程配置如何加载的源码体现,后面再补充

文章来源:https://blog.csdn.net/weixin_39439156/article/details/135341539
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。