SpringBoot配置你不知道的秘密

1,837 阅读4分钟

1.前言

使用SpringBoot框架进行开发的时候,通常会在resources目录下创建一个名为application.yml的配置文件,把需要用到的属性放在application.yml文件中。不知道你有没有想过,为什么配置文件要放在resources目录下,可不可以放在其他目录下面?配置文件名称可不可以使用其它名称?如何指定多环境配置?为什么通过Environment对象可以读取到配置属性?为什么运维在启动脚本中指定了配置文件路径后,项目中的配置文件就不生效了?

伴随着这些问题的困扰,我们需要去探索一下SpringBoot框架是如何加载配置。

2.配置加载

2.1 准备Environment

使用过SpringBoot框架的你应该很清楚,在SpringApplication.run()方法中会创建Environment对象,在创建完Environment对象后会发布ApplicationEnvironmentPreparedEvent事件

2.2 监听ApplicationEnvironmentPreparedEvent事件

既然有事件发布就会有监听的地方,监听类为ConfigFileApplicationListener,实现EnvironmentPostProcessorSmartApplicationListener接口

在监听事件处理方法中,先从spring.factories文件中加载EnvironmentPostProcessor接口的实现,之后将ConfigFileApplicationListener也放入到Environment处理器中

2.3 获取配置文件路径

配置文件路径的获取,先从spring.config.additional-location属性中获取配置文件路径;接着判断是否指定spring.config.location属性,指定则添加对应的路径,未指定则添加默认的配置路径。此处可以得出一个很重要的结论,那就是如果指定 spring.config.location属性,就不会加载private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/";路径下的配置文件。如果需要指定额外的配置文件路径并加载默认路径下的配置文件,应使用spring.config.additional-location属性而不是spring.config.location属性,默认路径的定义正好解释了resources目录下定义的配置文件会被加载的原因。

2.4 配置文件优先级

配置文件路径获取逻辑中可以看出,如果指定了spring.config.additional-location属性,会先放入该属性对应的路径值

默认配置路径解析后会进行倒序排序,排序后的配置路径为file:./config/,file:./config/*/,file:./,classpath:/config/,classpath:/,最终的配置路径为spring.config.additional-location属性指定的路径,file:./config/,file:./config/*/,file:./,classpath:/config/,classpath:/,由此也就明白了spring.config.additional-location属性指定的路径会覆盖默认路径的原因

2.5 获取配置文件名称

既然配置文件路径可以自定义,那么配置文件名称想想就知道也是可以自定义的。

可以看到如果指定了spring.config.name属性,则加载对应属性值作为配置文件名称,spring.config.name属性可以指定多个配置文件名称,名称之间以逗号的方式进行分隔;如果没有指定spring.config.name属性,则使用默认的名称private static final String DEFAULT_NAMES = "application";,由此也就明白了配置文件名称定义为application的原因

2.6 加载配置

在了解完配置文件路径、配置文件名称处理之后,就可以开始加载指定路径下指定名称的配置文件了

2.6.1 策略模式加载配置

如你所知,常用的配置文件有两种类型,一种以.properties.xml结尾,一种以yamlyml结尾,针对不同类型需要不同的加载器进行加载

2.6.2 配置属性构建Map

此处以YamlPropertySourceLoader为例

配置文件经过加载后,会组装成key、value的形式

2.6.3 Map构建PropertySource

PropertySource构建很简单,直接以配置文件名称和配置内容Map进行构造

2.6.4 构建Document

构建Document的目的是设置当前文档对应的环境,用于后续的过滤,通过此部分代码,也可以搞明白一件事情,那就是可以通过spring.profiles来指定环境,通过spring.profiles.active来激活对应的环境。

spring:
  profiles:
    active: dev

---
spring:
  profiles: dev
student:
  id: 10002
  name: student properties dev

---
spring:
  profiles: test
student:
  id: 10003
  name: student properties test

---
spring:
  profiles: product
student:
  id: 10004
  name: student properties product

2.6.5 过滤Document

在2.6.4中设置了文档对应的环境

如果当前应用没有指定环境,那么就加载对应的文档;如果指定了环境,则会过滤出符合指定环境的文档。例如:当前应用指定了dev环境,那么只会加载定义了

spring:
  profiles: dev

的文档或者加载名称为application-dev.yml配置文件

2.7 配置放入Environment

配置加载完成之后,会将配置文件对应的PropertySource加入到Environment对象的propertySources属性中,因此我们可以通过Environment对象来获取对应的配置属性。

到此,所有的问题都有了答案,困惑的你也会醍醐灌顶,心情变得舒畅了,人也变得更加自信了。