Spring Boot - 多环境配置
# 简介
在实际的项目开发中,一个项目通常会存在多个环境,例如,开发环境、测试环境和生产环境等。不同环境的配置也不尽相同,例如开发环境使用的是开发数据库,测试环境使用的是测试数据库,而生产环境使用的是线上的正式数据库。
Profile 为在不同环境下使用不同的配置提供了支持,我们可以通过激活、指定参数等方式快速切换环境。
# 多 Profile 文件方式
Spring Boot 的配置文件共有两种形式:.properties
文件和 .yml
文件,不管哪种形式,它们都能通过文件名的命名形式区分出不同的环境的配置,文件命名格式为:
application-{profile}.properties/yml
其中,{profile}
一般为各个环境的名称或简称,例如 dev、test 和 prod 等等,这个根据自己的场景来定义。
# 环境配置
resources 下添加 4 个配置文件:
- application.yml:主配置文件,任意时候都生效
- application-dev.yml:开发环境配置文件
- application-test.yml:测试环境配置文件
- application-prod.yml:生产环境配置文件
定义了这些文件,那么想使用 dev 环境的配置,则在主配置文件切换环境:
spring:
profiles:
active: dev # 对应 {profile}
2
3
则代表使用 application-dev.yml
的配置信息。
值得注意的是:application.yml
主配置文件不管任何环境都会生效。
当 application-{profile}.yml
文件和 application.yml
文件的配置项都相同的情况下,profile 优先级高于 application 的配置。
也可以额外添加生效文件,而不是激活替换。比如:
spring:
profiles:
active: dev
include:
- test
- prod
2
3
4
5
6
# Profile 分组
当我们想使用多个环境的配置文件时候,可以这样:
spring:
profiles:
active: dev,test
2
3
当然也可以进行分组:
spring:
profiles:
group:
youngkbt: dev,test
2
3
4
然后激活 youngkbt 组
spring:
profiles:
active: youngkbt
2
3
运行 jar 包的时候也可以覆盖配置文件对环境的配置:java –jar xxx.jar --spring.profiles.active=dev
。
# @Profile 注解
当配置了环境变量,那么就对应的环境变量配置文件就会生效,这是针对变量而言,此外我们可以指定哪些组件在什么环境才允许被加载到 Spring 容器里。
比如指定某个组件只有在 dev 环境才被加载到容器里,如:
@Profile("dev")
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello Spring Boot";
}
}
2
3
4
5
6
7
8
9
10
此时该容器在 dev 环境才会注入到容器里,也就是处于其他环境,访问 /hello
是失效的。
# 外部化配置
场景:线上应用如何 快速修改配置,并应 用最新配置?
- SpringBoot 使用 配置优先级 + 外部配置 简化配置更新、简化运维。
- 只需要给
jar
应用所在的文件夹放一个application.yml
最新配置文件,重启项目就能自动应用最新配置
# 配置优先级
Spring Boot 允许将 配置外部化,以便可以在不同的环境中使用相同的应用程序代码。
我们可以使用各种 外部配置源,包括 Java Properties 文件、YAML 文件、环境变量和命令行参数。
@Value
可以获取值,也可以用 @ConfigurationProperties
将所有属性绑定到 java object 中。
以下是 SpringBoot 属性源加载顺序。后面的会覆盖前面的值。由低到高,高优先级配置覆盖低优先级:
- 默认属性(通过
SpringApplication.setDefaultProperties
指定的) @PropertySource
指定加载的配置(需要写在@Configuration
类上才可生效)- 配置文件(application.properties/yml 等)
- RandomValuePropertySource 支持的
random.*
配置(如:@Value("${random.int}")
) - OS 环境变量
- Java 系统属性(
System.getProperties()
) - JNDI 属性(来自
java:comp/env
) - ServletContext 初始化参数
- ServletConfig 初始化参数
- SPRING_APPLICATION_JSON 属性(内置在环境变量或系统属性中的 JSON)
- 命令行参数
- 测试属性。(
@SpringBootTest
进行测试时指定的属性) - 测试类
@TestPropertySource
注解 - Devtools 设置的全局属性。(
$HOME/.config/spring-boot
)
结论:配置可以写到很多位置,常见的优先级顺序:命令行 > 配置文件 > springapplication 配置。
Spring Boot 读取 application.yml 配置文件位置也是有优先级的:
配置文件优先级 如下:(后面覆盖前面)
- jar 包内 的
application.properties/yml
- jar 包内 的
application-{profile}.properties/yml
- jar 包外 的
application.properties/yml
- jar 包外 的
application-{profile}.properties/yml
建议用一种格式的配置文件。如果 .properties
和 .yml
同时存在,则 .properties
优先。
结论:包外 > 包内。同级情况:profile配置 > application 配置。
所有参数均可由命令行传入,使用 --参数项=参数值
,将会被添加到环境变量中,并优先于 配置文件。
比如 java -jar app.jar --name="Spring"
,可以使用 @Value("${name}")
获取。
演示场景:
- 包内:application.properties 的
server.port=8000
- 包内:application-dev.properties 的
server.port=9000
- 包外:application.properties 的
server.port=8001
- 包外: application-dev.properties 的
server.port=9001
启动端口:命令行 > 9001
> 8001
> 9000
> 8000
# 外部配置
SpringBoot 应用启动时会自动寻找 application.properties
和 application.yml
位置,进行加载。顺序如下:
当前路径(jar 包根目录下)的配置文件优先级大于项目 resource 下
- 在项目所在的位置下 config 目录下的 application.yml 大于项目所在的位置的 application.yml
- 项目 resource 下 config 目录下的 application.yml 大于项目 resource 下的 application.yml
总结:
- 命令行 > 包外 config 直接子目录 > 包外 config 目录 > 包外根目录 > 包内目录
- 同级比较:
- profile 配置 > 默认配置
- properties 配置 > yaml 配置
规律:最外层的最优先。
- 命令行 > 所有
- 包外 > 包内
- config 目录 > 根目录
- profile > application
配置不同就都生效(互补),配置相同高优先级覆盖低优先级。