天天看点

SpringBoot之浅析配置项解析(二)

我们在上一篇文章中简单的说了一些SpringBoot配置属性相关的一些内容,我们在这篇文章中接着上一篇的文章继续进行分析。我们在上一篇文章中提到了这样一个类:ConfigFileApplicationListener,从类名来看的话这是一个配置文件应用监听器,这个类主要的一个作用是在 refresh context之前解析默认的配置文件。首先我们来看一下它的UML类图:

SpringBoot之浅析配置项解析(二)

ConfigFileApplicationListener实现了EnvironmentPostProcessor和SmartApplicationListener这两个接口,从上图中我们可以看到SmartApplicationListener其实是继承了ApplicationListener这个接口的。SmartApplicationListener这个类相比于ApplicationListener多了两个方法,一个是用来检测是否支持给定的类型,一个是用来检测得到的source type。EnvironmentPostProcessor这个接口的作用是在refresh application context之前定制化应用的环境配置信息,需要说明的是,实现这个接口的类必须要在spring.factories进行配置。大家可以想一下这里为什么要这样。既然ConfigFileApplicationListener也是一个监听器类,那么它肯定会监听某些动作的发生,我们在之前的文章中说过,在org.springframework.boot.SpringApplication#run(java.lang.String… args)这个方法中会负责SpringBoot的整个启动工作,在这里有这样的一段代码:

顺着listeners.starting();这个方法往下扒的话,你就会找到调用org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEvent这个方法的地方,这个调用链不算很负责,这里就不再多说了。我们直接进入到ConfigFileApplicationListener#onApplicationEvent这个方法中:

但是啊但是,在onApplicationEvent中有两个条件判断,你通过listeners.starting()这个调用链一直跟踪到这里的话你会发现,这两个条件都不满足listeners.starting()的调用,那么是在什么地方触发这个监听事件的呢?在org.springframework.boot.SpringApplication#prepareEnvironment这个方法中,我们在上一篇文章中介绍了其中的一些代码,这里再看一段代码:

org.springframework.boot.SpringApplicationRunListeners#environmentPrepared

org.springframework.boot.context.event.EventPublishingRunListener#environmentPrepared

从上面的代码中我们可以看到在执行listeners.environmentPrepared(environment);

的时候,会调用ConfigFileApplicationListener#onApplicationEvent这个方法,并且所传入的ApplicationEvent是ApplicationEnvironmentPreparedEvent,所以这里会调用ConfigFileApplicationListener#onApplicationEvent中的org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent方法。我们进入到onApplicationEnvironmentPreparedEvent方法中看一下:

postProcessEnvironment的源码如下:

在上面的代码中,我们目前需要重点关注的就是ConfigFileApplicationListener#addPropertySources这个方法:

RandomValuePropertySource.addToEnvironment

上面这段代码的意思就将RandomValuePropertySource添加到systemEnvironment的后面,到目前为止我们的MutablePropertySources#propertySourceList中的元素顺序为:commandLineArgs、servletConfigInitParams 、servletContextInitParams 、jndiProperties 、systemProperties 、systemEnvironment、random。我们接着分析new Loader(environment, resourceLoader).load();这段代码,这个代码中的内容比较多,我们也不是全部都要关注,这里我们先把Profile相关的内容先剥离出去。我们直接到这里:

我们先来看上面标记为1)处的代码:

我们接着看2)处的代码:

所以上面while的这一段代码我们可以简化为这样(极其简化):