前几天的时候,项目里有一个需求,需要一个开关控制代码中是否执行一段逻辑,于是理所当然的在 yml
文件中配置了一个属性作为开关,再配合 nacos
就可以随时改变这个值达到我们的目的,yml文件中是这样写的:
switch: turnOn: on
程序中的代码也很简单,大致的逻辑就是下面这样,如果取到的开关字段是 on
的话,那么就执行 if
判断中的代码,否则就不执行:
@Value("${switch.turnOn}") private String on; @GetMapping("testn") public void test(){ if ("on".equals(on)){ //TODO } }
但是当代码实际跑起来,有意思的地方来了,我们发现判断中的代码一直不会被执行,直到debug一下,才发现这里的取到的值居然不是 on
而是 true
。
看到这,是不是感觉有点意思,首先盲猜是在解析yml的过程中把 on
作为一个特殊的值进行了处理,于是我干脆再多测试了几个例子,把yml中的属性扩展到下面这些:
switch: turnOn: on turnOff: off turnOn2: 'on' turnOff2: 'off'
再执行一下代码,看一下映射后的值:
可以看到,yml中没有带引号的 on
和 off
被转换成了 true
和 false
,带引号的则保持了原来的值不发生改变。
到这里,让我忍不住有点好奇,为什么会发生这种现象呢?于是强忍着困意翻了翻源码,硬磕了一下SpringBoot加载yml配置文件的过程,终于让我看出了点门道,下面我们一点一点细说!
因为配置文件的加载会涉及到一些SpringBoot启动的相关知识,所以如果对SpringBoot启动不是很熟悉的同学,可以先提前先看一下Hydra在古早时期写过一篇 Spring Boot零配置启动原理 预热一下。下面的介绍中,只会摘出一些对加载和解析配置文件比较重要的步骤进行分析,对其他无关部分进行了省略。
加载监听器
当我们启动一个SpringBoot程序,在执行 SpringApplication.run()
的时候,首先在初始化 SpringApplication
的过程中,加载了11个实现了 ApplicationListener
接口的拦截器。
这11个自动加载的 ApplicationListener
,是在 spring.factories
中定义并通过 SPI
扩展被加载的: