SpringBoot外化配置源码解析:命令参数获取文件加载( 二 )


下面 , 我们通过源代码的追踪来分析这一过程 。 该事件同样是在 SpringApplication 的 run方法中来完成的 。 前半部分的调用过程与上一节命令行参数获取的方法调用一样 , 不同的是当执行到 prepareEnvironment 中 , 当执行完上一节中的 configureEnvironment 方法之后 , 便通过事件发布来通知监听器加载资源 。
private ConfigurableEnvironment prepareEnvironment{SpringApplicationRunL isteners listeners ,ApplicationArguments applicationArguments) {//获取或创建环境ConfigurableEnvironment environment = getOrCreateEnvironment();//配置环境 , 主要包括 PropertySources 和 activeProfiles 的配置configureEnvironment( environment, applicat ionArguments . getSourceArgs());// listener 环境准备(之前章节已经提到listeners . environmentPrepared( environment);}}该事件监听器通过 EventPublishingRunListener 的 environmentPrepared方法来发布一个 ApplicationEnvironmentPreparedEvent 事件 。
public class EventPublishingRunL istener implements SpringApplicationRunListener ,Ordered {@Overridepublic void environmentPrepared(ConfigurableEnvironment environment) {this. initialMulticaster. multicastEvent(new ApplicationEnvironmentPre-paredEvent(this. application, this.args, environment));}在 META-INF/spring .factories 中注册的 ConfigFileApplicationListener 会监听到对应事件 , 并进行相应的处理 。 spring.factories 中 ConfigFileApplicationListener 的注册配置如下 。
# Application Listenersorg. springframework. context . ApplicationListener=\org. springframework . boot . context . config. ConfigFileApplicationListener在 ConfigFileApplicationListener 类中我们会看到很多与配置文件加载相关的常量 。 public class ConfigFileApplicationListenerimplements EnvironmentPostProcessor, SmartApplicationListener, Ordered {//默认的加戴配置文件路径private static final String DEFAULT_ SEARCH_ LOCATIONS ="classpath:/ , classpath:/config/ ,file:./, file:./config/";//默认的配置文件名称private static final String DEFAULT_ NAMES = " application";//激活配置文件的属性名public static final String ACTIVE_ PROFILES_ PROPERTY = " spring. profiles. active";}我们通过这些基本的常量 , 已经可以看出默认加载配置文件的路径和默认的名称了 。 再回到刚才的事件监听 , 入口方法为 ConfigFileApplicationListener 的 onApplicationEvent 方法 。
@Overridepublic void onApplicationEvent (ApplicationEvent event) {//对应前面发布的事件 , 执行此业务逻辑if (event instanceof ApplicationEnvironmentPreparedEvent) {onApplicationEnvironmentPreparedEvent( (Applicat ionEnvironmentPrepared-Event) event);if (event instanceof Applicat ionPreparedEvent) {onApplicationPreparedEvent(event);}上面代码中调用的 onApplicationEnvironmentPreparedEvent 方法如下,该方法会获得注册的处理器 , 遍历并依次调用其 postProcessEnvironment 方法 。
private void onApplicat ionEnvi ronmentPreparedEvent( Applicat ionEnvironmentPre -paredEvent event) {List postProcessors = loadPostProcessors();postProcessors . add(this);Annotat ionAwareOrderComparator . sort (postProcessors);//遍历并依次调用其 postProcessEnvironment 方法for (EnvironmentPostProcessor postProcessor : postProcessors) {postProcessor. postProcessEnvironment ( event . getEnvironment( ) ,event . getSpringApplication());}其中 EnvironmentPostProcessor 接口的实现类也是在 META-INF/sprig.factories 文件中注册的 。
# Environment Post 处理器配置org. springframework. boot . env. EnvironmentPostProcessor=\org. springframework . boot . cloud . CloudF oundryVcapEnvironmentPostProcessor, \org. springframework. boot . env. SpringApplicationJsonEnvironmentPostProcessor,\org . springframework . boot. env . SystemEnvironmentPropertySourceEnvironmentPostProcessorConfigFileApplicationListener 本身也是 EnvironmentPostProcessor 接口的实现类我们跟着ConfigFileApplicationListener 中 postProcessEnvironment 的调用链路代码一-直往下看 , 会发现最后在其内部类 Loader 的 load 方法中进行配置文件的加载操作 。 其中关于文件路径及其名称的组合代码如下 。
private void load(String location, String name, Profile profile,DocumentFilterFactory filterFactory, DocumentConsumer consumer) {Set processed = new HashSet<>() ;for (PropertySourceLoader loader : this. propertySourceLoaders) {for (String fileExtension : loader . getFileExtensions()) {if (processed . add(fileExtension))loadForFileExtension(loader, location + name, "." + fileExtension,profile, filterFactory, consumer);}在该方法中可以看到 loadForFileExtension 的第二个参数“文件路径+名称"和第三个参数“扩展名称”的拼接组成方式 。
location 默认值就是常量 DEFAULT_ SEARCH_ LOCATIONS 的值 。
在 for 循环中遍历的 PropertySourceLoader 也是在 META-INF/spring.factories 中注册的 ,