Spring Boot 如何处理配置文件中的占位符
在 Spring Boot 中,处理配置文件中的占位符(placeholders)是一项非常常见且重要的功能。它允许在配置文件中引用其他配置项、环境变量或系统属性,从而实现灵活、动态的配置管理。
一、占位符的基本语法
Spring Boot 使用 {} 或 $ENV_VAR 的语法来表示占位符。
1. ${property.name:default_value}
- ${...}:引用配置属性。
- :default_value 是可选的,表示如果属性未定义,则使用默认值。
示例:
# application.yml
app:
name: MyApp
version: 1.0
description: ${app.name} version is ${app.version:unknown}
home: ${HOME} # 引用系统环境变量
temp-dir: ${TEMP_DIR:/tmp} # 环境变量不存在时使用默认值
# application.properties
app.name=MyApp
app.version=1.0
app.description=${app.name} version is ${app.version:unknown}
app.home=${HOME}
app.temp-dir=${TEMP_DIR:/tmp}
二、支持的占位符来源
Spring Boot 会从多个 PropertySource 中查找占位符对应的值,优先级如下(由高到低):
- 命令行参数(--server.port=8081)
- 环境变量(SERVER_PORT=8081)
- 配置文件(application.yml / application.properties)
- @PropertySource 注解加载的配置
- 默认属性(通过 SpringApplication.setDefaultProperties() 设置)
三、在代码中使用占位符
1. 使用 @Value 注解读取
@Component
public class AppConfig {
@Value("${app.name}")
private String appName;
@Value("${app.version:1.0}") // 提供默认值
private String version;
@Value("${HOME}") // 读取环境变量
private String homePath;
// getter...
}
2. 使用 @ConfigurationProperties 绑定(推荐)
更推荐使用类型安全的配置绑定方式。
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String version = "1.0"; // 默认值可在代码中设置
private String description; // 会自动解析 ${app.name} version is ${app.version}
private String home;
// getter & setter
}
注意:@ConfigurationProperties 支持占位符解析(如 ${app.name}),但不支持 SpEL 表达式(如 #{systemProperties['user.dir']}),而 @Value 支持 SpEL。
四、跨配置文件引用
可以在一个配置文件中引用另一个配置文件中定义的属性。
# application.yml
database:
host: localhost
port: 5432
url: jdbc:postgresql://${database.host}:${database.port}/mydb
Spring Boot 会自动解析 ${database.host} 和 ${database.port}。
五、使用环境变量覆盖配置
这是 Spring Boot 的强大之处:无需修改配置文件,通过环境变量即可动态覆盖配置。
例如:
export DATABASE_HOST=db-prod.example.com
java -jar myapp.jar
即使 application.yml 中 database.host=localhost,运行时也会使用 db-prod.example.com。
六、高级用法:Profile 特定配置
结合 spring.profiles.active,可以实现不同环境的动态配置。
# application.yml
spring:
profiles:
active: dev
---
# application-dev.yml
app:
name: MyApp-Dev
debug: true
---
# application-prod.yml
app:
name: MyApp-Prod
debug: false
然后在其他配置中引用:
logging:
level: ${app.debug:INFO}
七、注意事项
- 循环引用:避免配置项之间形成循环引用,如:
a: ${b}
b: ${a} # 错误!会导致解析失败
- 类型转换:@Value 注解支持基本类型转换(如 int, boolean),但复杂类型需自定义 Converter。
- 延迟解析:某些场景下(如 @ConditionalOnProperty),占位符可能在容器初始化早期就被解析,确保值已加载。
- 安全性:避免在日志中打印包含敏感信息的配置(如密码),即使使用了占位符。
八、调试占位符解析
如果占位符未正确解析,可以启用 debug 模式查看:
java -jar myapp.jar --debug
或在 application.properties 中:
logging.level.org.springframework=DEBUG
总结
方法 | 适用场景 | 是否推荐 |
${...} | 配置文件内引用 | 强烈推荐 |
@Value | 简单字段注入 | |
@ConfigurationProperties | 类型安全的配置绑定 | 强烈推荐 |
环境变量 | 动态覆盖配置 | (生产环境必备) |
最佳实践:
- 使用 @ConfigurationProperties + @Validated 实现类型安全配置。
- 利用环境变量实现“一次构建,多环境部署”。
- 合理使用默认值(:default)提高健壮性。