SpringBoot配置文件解析之 addPropertySources 方法剖析

分享 未结 精帖 0 3054
KSE-music
KSE-music LV4 2018-08-14
悬赏:20积分
一、将属性源添加到指定的环境
RandomValuePropertySource.addToEnvironment(environment);该方法很简单,就是把随机值属性源添加到名称为systemEnvironment的属性源后面
作用:可以在配置文件里,配置获取随机数,如:random.int、random.long
二、利用内部类Loader加载器去加载候选的属性源和配置激活的profile
1、构造了一个Loader对象,构造器参数分别是当前应用环境和资源加载器
2、调用方法load如下图所示:


接下来我们一行一行来分析每一句代码:
this.propertiesLoader = new PropertySourcesLoader();依旧见其名知其义,首先创建一个属性源加载器,它的无参构造器调用了重载构造器并接收一个易变的属性源MutablePropertySources(接口PropertySources的默认实现,用于操作属性源,调整属性源优先级顺序)。然后通过老手法去查找属性源加载器,即spring.factories中key为org.springframework.boot.env.PropertySourceLoader的值,这里获取到两个,一个是PropertiesPropertySourceLoader(解析文件扩展名为properties和xml的文件),另一个是YamlPropertySourceLoader(解析文件扩展名为yml和yaml的文件)。

this.activatedProfiles = false;设置profile为未激活状态。

this.profiles = Collections.asLifoQueue(new LinkedList<Profile>());创建一个后入先出的队列。

this.processedProfiles = new LinkedList<Profile>();构建一个收集已经处理过的profile的集合。

Set<Profile> initialActiveProfiles = initializeActiveProfiles();初始化激活的profile,逻辑就是在当前环境下查找key有没有spring.profiles.active和spring.profiles.include的属性,我们这里都没有,所以直接返回了一个空的集合。

this.profiles.addAll(getUnprocessedActiveProfiles(initialActiveProfiles));获取未处理的profile并添加到队列中,因为我们当前环境中也没有设置,所以也返回了集合。

因为此时此刻,我们都还没设置profile,所以spring就构建了一个默认的profile(构建的时候已标识)并添加到队列中。

this.profiles.add(null);该代码貌似很屌的样子,源码中已经给出解释了,这里我们就不关公面前耍大刀了。

接下来就是循环队列里的profile了。

Profile profile = this.profiles.poll();这里取出的肯定就是null了,因为这就是前面刚故意加入的null。
getSearchLocations()获取搜索配置文件路径,如果环境中存在key为spring.config.location的属性,则将其添加到待搜索的集合中。因为我们这里没有,所以就直接使用了默认的搜索路径了,分别是classpath:/,classpath:/config/,file:./,file:./config/。
搜索路径优先级:file:./config/ > file:./ > classpath:/config/ > classpath:/
接下来就开始处理每一个路径了,首先是判断location是不是目录(以斜杠结尾的表示目录),如果是文件则直接处理该文件。因为我们这里都不是,所以需要拼上配置文件名。getSearchNames()就是获取配置文件名,如果当前环境中存在spring.config.name属性值,则添加到待搜索集合,因为我们这里没有设置,所以依然使用的是默认文件名即application。

因为我的配置文件放在classpath:/config/ ,所以我就直接跳到第三个路径讲解。我们来看私有方法load如下:


前面比较简单,我们直接进入方法doLoadIntoGroup,在解析完配置文件后,调用了handleProfileProperties方法,一看就是处理profile的,因为我们可能在默认的配置文件里设置 spring.profiles.active。



SpringProfiles springProfiles = bindSpringProfiles(propertySource);就是从当前解析的属性源中获取spring.profiles.active和spring.profiles.include的值并设置到SpringProfiles对象上,我这里的active是local(表示本地环境启动)

maybeActivateProfiles(springProfiles.getActiveProfiles());这里首先判断profile是否已经激活,没激活则把默认配置文件中解析的local添加到profile队列中,同时将标志位activatedProfiles置为true表示profile已经激活,最后再移除没有处理的默认profile。
划重点:
这里就解释了,为什么spring要在前面加个null,为什么在循环第二个profile的时候,profile不是default却变成了我们在默认配置文件里设置的local。
this.processedProfiles.add(profile);将当前已处理完的profile加入到已处理的profile集合中。
当第二次从队列中取出profile时,队列已经空了,自然这个while循环也就结束了。

接下来的处理,其实和第一次几乎没什么两样,唯一不同的是,此时profile是有值的,所以最终解析的配置文件名就变成下图所示的样子:


这也解释了为什么配置文件中间要加一个 " - "了。

loadIntoGroup(group, location + name + "-" + profile + "." + ext,profile);这里是为了解决那些把profile写在和配置文件名一样的人,如:你命名了一个application-dev.ym里面又存在一个spring.profiles.active=dev,看来官方也是良苦用心啊!

三、将解析的属性源添加到环境中
addConfigurationProperties(this.propertiesLoader.getPropertySources());
这里大致就是构建一个名为applicationConfigurationProperties的属性源,然后添加到MutablePropertySources中,这里使用的addLast,所以当前它的优先级是最低的。
此时环境里属性源如下图所示:

回帖
  • 消灭零回复