浅谈如何将Spring Boot的启动配置放在配置管理系统中

楔子

俗话说得好,没有需求就没有变通。之前所在项目的技术栈中并没有用到spring boot,后来一次的产品重构中在某个服务中便添加进去了。在业务开发中spring boot用着确实挺爽的,但是由于这和之前的产品风格不一致,导致在运维部署的时候带来了一些额外的负担 – spring boot的应用配置信息需要在本地配置文件文件中写死。这样就得在不同的环境中进行修改。这时候有人肯定会想可以使用spring boot提供的多环境配置,这个方式确实在3-5个环境中还可以这样玩,一旦环境数量达到几十个的时候,这样配置会是一种灾难。

为了解决这种多环境下的配置信息管理问题,我们决定将spring boot的启动配置信息转移到统一配置管理系统中(这里采用的是zookeeper,其他的方式也类似)。这也是因为其他产品的配置信息也都是在zookeeper中进行管理的。

正文

其实实现的思路很简单,就是在启动配置文件application.properties被加载以前,根据从zookeeper中获取到的信息组装成一份完整的application.properties文件。

一、错误的方案

一开始我们在没有根据的情况的下凭空臆断 – application.properties配置文件是在spring容器被加载完毕后读取的。此时的代码被写成了以下形式。

mark

这里创建了一个用来监听Spring容器是否被加载的监听器,然后在加载成功以后执行从zookeeper获取配置信息,然后再生成application.properties的逻辑。此时的运行结果就是系统找不到application.properties,无法正确启动。此时我们意识到application.properties文件的加载时间并不是所想象的那样。

二、application.properties的加载逻辑

为了让spring boot可以顺利的解析到我们动态生成的application.properties,我们需要打开spring boot的源码来仔细研究一下其加载的正确时间。

这里有人会说,难道不能在spring boot启动之前就获取配置信息然后生成application.properties文件吗?回答是肯定可以的(例如以下这种写法),但是如果真的这么做了,这篇文章不就没有那么多干货了。

mark

打开源码第一层,可以看到如下代码

mark

  1. 这里创建了一个SpringApplication的对象,初始化了一系列的成员变量
  2. 调用了该对象的一个核心方法run

这里SpringApplication的初始化不是本文的重点,这里就略过,我们现在来看看run方法里面都做了些什么事情

mark

里面的内容比较多,这里只挑一些比较关键的且与配置文件加载相关的部分来说明

  1. 这里创建了一个SpringApplicationRunListeners它是一个SpringApplicationRunListener的集合,用来在spring boot的不同生命周期,广播相应的事件
  2. 在run一开始的时间广播
  3. 在context刷新完成后,run结束前广播
  4. 实例化一个全局的系统参数对象
  5. 创建spring boot的配置环境,也就是在这里会加载application.properties

这会让我们来看一下(5)究竟一些什么事情

mark

  1. 获取一个环境配置信息
  2. 装载配置信息
  3. SpringApplicationRunListeners再次在环境建立好的时候广播消息,此时所有监听ApplicationEnvironmentPreparedEvent事件的监听器都会被触发。

这时我们追踪到了和application.properties相关的监听器为ConfigFileApplicationListener

mark

mark

mark

关于onApplicationEnvironmentPreparedEvent方法里面做的事情这里简要说明一下。EnvironmentPostProcessor是spring boot提供动态管理配置文件的扩展接口,支持自己去扩展。这里ConfigFileApplicationListener也被当做是扩展的一种(实现了EnvironmentPostProcessor接口),所以this也被添加到扩展集合中。后面便是将这些扩展进行排序,依次调用他们所定义的postProcessEnvironment方法。

这里我们尤为需要关心的是this所提供的postProcessEnvironment方法

mark

mark

调用load前的部分可以理解为将配置信息添加到环境配置中,这里不做详细研究,重点我们来看一下load里面的逻辑

mark

  1. 创建一个配置加载器
  2. 根据规则加载配置信息
  3. 默认遍历classpath:/,classpath:/config/,file:./,file:./config/路径下的所有文件
  4. 在(3)中指定的路径下面扫描指定文件名称的配置文件,这里默认是application
  5. 这里是加载配置文件的核心逻辑,下面再进行讲解
  6. 最后将加载到的配置文件信息全部添加至环境配置中

下面让我们快速看一下(5)所描述的核心调用链

mark

mark

mark

mark

mark

虽然ConfigFileApplicationListener监听器执行的逻辑有些绕,但是概括起来就是在指定的路径下扫描指定名称的配置文件,然后根据文件类型调用不同的配置文件加载器,最后将解析出来的内容放置在环境配置中,以供spring boot后续使用。

三、结论

现在我们可以很明确知道application.properties配置的正确加载时间,就是spring boot在触发ApplicationEnvironmentPreparedEvent事件之后。因此我们可以自己实现一个监听器用来监听ApplicationEnvironmentPreparedEvent事件的发生,来执行我们生成application.properties配置文件的逻辑。

实现逻辑可以参照如下所示

mark


至此整个分析过程已经全部结束。现在做一下下期预告,我们将从一次差点被玩坏的Zookeeper来讲讲关于它的权限控制

欢迎关注微信公众号,在这里可以提前看到下一期文章哦~

mark

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值