上一篇Blog详细学习了YAML的语法、yml配置文件的编写以及SpringBoot是如何把配置文件自动绑定到代码中的,本篇Blog还是专注于讨论关于SpringBoot配置的事情,包括在真实的开发案例中,SpringBoot是如何进行多环境切换配置以及SpringBoot包含哪些配置文件,这些配置文件在绑定读取时又有哪些优先级。
Profile多环境配置
在实际的项目开发中,一个项目通常会存在多个环境,例如,开发环境、测试环境、预发环境以及生产环境等。不同环境的配置也不尽相同,例如开发环境使用的是开发数据库,测试环境使用的是测试数据库,而生产环境使用的是线上的正式数据库,Profile 为在不同环境下使用不同的配置提供了支持,我们可以通过激活、指定参数等方式快速切换环境
Profile配置方式
Spring Boot 的配置文件共有两种形式:.properties
文件和 .yml
文件,不管哪种形式,它们都能通过文件名的命名形式区分出不同的环境的配置,文件命名格式为:
application-{profile}.properties/yml
其中,{profile} 一般为各个环境的名称或简称,例如 dev、test 和 prod 等等,由于一般我们使用的配置文件是yml文件,所以这里只讨论yml文件的配置形式
我们可以添加 3 个配置文件,如下所示:
- application-dev.yml:开发环境配置
- application-test.yml:测试环境配置
- application-prod.yml:生产环境配置
在 applcation.yml 文件中指定默认服务端口号为 8080,并通过以下配置来激活开发环境的 profile。
#默认配置
server:
port: 8080
#切换配置
spring:
profiles:
active: dev #激活开发环境配置
在 application-dev.yml 中指定开发环境端口号为 8081,配置如下
#开发环境
server:
port: 8081
在 application-test.yml 中指定测试环境端口号为 8082,配置如下
#测试环境
server:
port: 8082
在 application-prod.yml 中指定生产环境端口号为 8083,配置如下
#生产环境
server:
port: 8083
重启 Spring Boot 主程序,查看控制台输出,如下图:
通过上图可以看到,我们指定的开发环境(dev) Profile 生效了,且服务器端口为 8081
Profile激活方式
但是我们发现一个问题,就是每次切换环境还需要去配置里指定,然后通过修改dev为test或prod来切换项目环境 , 这样做的话每次切换环境都要重新改一下配置 , 而且如果不小心把本地改动提交到*仓库了 , 可能会影响到其他同事拉取代码,maven中提供了一个profile配置项,可以在打包时动态的指定环境配置.结合idea使用 , 我们可以实现不动任何代码来随意的切换我们的工作环境。
1 更改spring.profiles.active
首先我们修改原有的配置激活固定值为配置值:
spring.profiles.active=@env@
2 配置pom.xml
然后修改pom.xml,在其中加入一些profile信息:
<profiles>
<!-- 开发环境 -->
<profile>
<id>dev</id>
<properties>
<env>dev</env><!-- 之前写的@env@就是通过这里的配置切换环境 -->
</properties>
<activation>
<activeByDefault>true</activeByDefault><!-- 指定缺省环境 -->
</activation>
</profile>
<!-- 测试环境 -->
<profile>
<id>test</id>
<properties>
<env>test</env>
</properties>
</profile>
<!-- 生产环境 -->
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
</profiles>
3 切换Profile
修改完配置后,刷新下Maven面板我们就能在侧边看到Profiles的面板选项了,这个时候我们切换到prod然后重启服务器就可以看到生产环境的端口信息8083了。
SpringBoot配置加载顺序
Spring Boot 不仅可以通过配置文件进行配置,还可以通过环境变量、命令行参数等多种形式进行配置。这些配置都可以让开发人员在不修改任何代码的前提下,直接将一套 Spring Boot 应用程序在不同的环境中运行
Spring Boot 配置优先级
以下是常用的 Spring Boot 配置形式及其加载顺序(优先级由高到低):
- 命令行参数
- 来自
java:comp/env
的 JNDI 属性 - Java 系统属性(System.getProperties())
- 操作系统环境变量
- RandomValuePropertySource 配置的 random.* 属性值
- 配置文件(YAML 文件、Properties 文件)
- @Configuration 注解类上的 @PropertySource 指定的配置文件
- 通过 SpringApplication.setDefaultProperties 指定的默认属性
以上所有形式的配置都会被加载,当存在相同配置内容时,高优先级的配置会覆盖低优先级的配置;存在不同的配置内容时,高优先级和低优先级的配置内容取并集,共同生效,形成互补配置
配置文件加载顺序
通常情况下,Spring Boot 在启动时会将 resources 目录下的 application.properties
或 apllication.yml
作为其默认配置文件,我们可以在该配置文件中对项目进行配置,但这并不意味着 Spring Boot 项目中只能存在一个 application.properties 或 application.yml,Spring Boot 项目中可以存在多个 application.properties
或 apllication.yml
以上优先级中我们重点关注配置文件的加载顺序,这个是我们最常用的配置手段,Spring Boot 启动时,会自动加载 JAR 包内部及 JAR 包所在目录指定位置的配置文件(Properties 文件、YAML 文件),下图中展示了 Spring Boot 自动加载的配置文件的位置及其加载顺序,同一位置下,Properties 文件优先级高于 YAML 文件
上图中的节点说明如下:
- /myBoot:表示 JAR 包所在目录,目录名称自定义;
- /childDir:表示 JAR 包所在目录下 config 目录的子目录,目录名自定义;
- JAR:表示 Spring Boot 项目打包生成的 JAR;
- 其余带有“/”标识的目录的目录名称均不能修改。
- 红色数字:表示该配置文件的优先级,数字越小优先级越高。
这些配置文件得优先级顺序,遵循以下规则:
- 先加载 JAR 包外的配置文件,再加载 JAR 包内的配置文件;
- 先加载 config 目录内的配置文件,再加载 config 目录外的配置文件;
- 先加载 config 子目录下的配置文件,再加载 config 目录下的配置文件;
- 先加载
appliction-{profile}.properties/yml
,再加载application.properties/yml
; - 先加载 .properties 文件,再加载 .yml 文件
我们做个实验
位于classpath:/config/
下的配置文件内容为:
#类路径下的 config 目录下
#端口号为8084
#上下文路径为 /helloWorld
server:
port: 8084
servlet:
context-path: /gcy
位于classpath:/
下的配置文件内容为:
#默认配置
server:
port: 8080
person:
name: tml
age: 30
pets:
-dog
-cat
-pig
car:
name: 蔚来es6
url:
domain: www.baidu.com
location: china
位于根目录下的配置文件为:
#项目根目录下
#上下文路径为 /tml
server:
servlet:
context-path: /tml
启动后发现启动信息为
根据 Spring Boot 默认配置文件优先级进行分析:
- 该项目中存在多个默认配置文件,其中根目录下 /config 目录下的配置文件优先级最高,因此项目的上下文路径为
/tml
; - 类路径(classpath)下 config 目录下的配置文件优先级高于类路径下的配置文件,该项目的端口号为8084;
以上所有配置项形成互补,所以访问路径为http://localhost:8084/tml/hello
。
但是有一点需要注意,如果当前激活指定了spring.profiles.active: @env@
某个配置文件,那么按照上述配置加载顺序走激活指定的Profile配置文件,如果不指定激活Profile,那么是不会加载appliction-{profile}.properties/yml
配置文件,按照上述配置顺序加载appliction.properties/yml
配置文件
总结一下
之前一直看不懂profile是干嘛的,现在终于知道了,是为了切换环境时使用不同配置身份用的,这个可比C#方便多了,记得之前拉代码的时候老会遇到配置被别人改到测试了,现在有了Maven的环境切换,方便多了,本地随便改。即使我们知道SpringBoot有这么多的配置优先级,其实实际用的时候我们也都是简单用,配置好启动身份后,我们一般只在类路径(classpath)下添加各个环境配置文件然后加载使用,避免混乱,但是大概了解下加载逻辑也便于之后方便排查问题。