Spring Boot 4.0 配置管理:Profile、环境变量与敏感配置
前言
开发环境连接本地参数,生产环境限制分页大小,测试环境又可能需要另一个区域。把这些差异全部写进一份 application.yml,最后很难判断某个值为什么没有生效。
Spring Boot 的配置系统不是简单的 YAML 解析。它会把配置文件、Profile、命令行参数、环境变量和代码默认值按顺序组合。
这篇教程会在现有工程中增加开发、生产 Profile 和一个区域环境变量,并通过接口观察最终生效的配置。
配套源码:dvsusan/spring-boot4-demo。
最终结果
完成后,同一份 JAR 可以启动出不同配置:
默认启动 -> dev / maxPageSize=50 / region=local
prod Profile -> prod / maxPageSize=20 / region=local
命令或环境变量覆盖 -> prod / maxPageSize=25 / region=cn-east所有结果都能通过同一个接口查看:
curl "http://localhost:8080/api/v1/system/config"配置从哪里来?
本项目涉及四层配置:
| 来源 | 示例 | 适合放什么 |
|---|---|---|
| Java 默认值 | maxPageSize = 100 | 保证对象可用,不承载环境差异 |
application.yml | 公共属性 | 所有环境共享的默认配置 |
application-dev.yml | 开发参数 | 本地调试、较详细日志 |
| 命令行/环境变量 | 端口、密码、部署区域 | 部署时动态覆盖和敏感信息 |

图 1:配置逐层进入最终属性对象,部署环境负责注入不应该提交到 Git 的敏感值。
后出现的来源不应该直接覆盖所有前序来源,具体优先级由 Spring Boot 决定。排查配置问题时,要看最终环境值,不要只盯某一份 YAML。
第 1 步:建立公共配置
打开 demo-web/src/main/resources/application.yml:
spring:
application:
name: demo-platform
profiles:
# 不指定启动参数时使用 dev 配置,方便本地学习。
active: ${SPRING_PROFILES_ACTIVE:dev}
server:
port: 8080
demo:
greeting:
enabled: true
message: "你好,%s,欢迎学习 Spring Boot 4"
environment:
label: local
max-page-size: 100
# 冒号后的 local 是环境变量缺失时的默认值。
region: ${DEMO_REGION:local}${SPRING_PROFILES_ACTIVE:dev} 的含义是:如果存在 SPRING_PROFILES_ACTIVE,使用它;否则使用 dev。
这适合学习项目,但生产项目不要把“默认 dev”当成安全策略。Profile 只决定加载哪组配置,不负责权限隔离,也不应该把生产密码写进生产 YAML。
第 2 步:绑定业务配置
创建 DemoEnvironmentProperties.java:
package com.susan.training.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 演示不同环境的业务配置。
*/
@ConfigurationProperties(prefix = "demo.environment")
public class DemoEnvironmentProperties {
// 当前环境名称,例如 dev、prod。
private String label = "local";
// 示例分页上限,用来演示配置项如何进入业务代码。
private int maxPageSize = 100;
// 部署区域既可由配置文件提供,也可由环境变量 DEMO_REGION 覆盖。
private String region = "local";
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getMaxPageSize() {
return maxPageSize;
}
public void setMaxPageSize(int maxPageSize) {
this.maxPageSize = maxPageSize;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
}通过 @ConfigurationProperties 绑定,比在业务代码里到处写 @Value 更容易维护。一组配置集中在一个对象里,还能为字段设置类型和默认值。
注册配置对象:
/**
* 注册业务配置属性。
*/
@Configuration
@EnableConfigurationProperties(DemoEnvironmentProperties.class)
public class WebPropertiesConfiguration {
}@EnableConfigurationProperties 会把带有 @ConfigurationProperties 的类注册进容器。
第 3 步:创建开发环境配置
创建 application-dev.yml:
demo:
environment:
# 开发环境使用更宽松的示例分页上限。
label: dev
max-page-size: 50
greeting:
# 用不同文案确认当前加载了开发配置。
message: "开发环境你好,%s"
logging:
level:
# 本地调试打开项目包的 DEBUG 日志。
com.susan.training: DEBUG这里只写与开发环境不同的值。公共结构仍由 application.yml 提供。
创建生产配置 application-prod.yml:
demo:
environment:
# 生产环境采用更保守的分页上限。
label: prod
max-page-size: 20
greeting:
# 生产配置覆盖问候模板。
message: "生产环境你好,%s"
management:
endpoint:
health:
# 不向普通调用方展示健康检查内部详情。
show-details: never生产环境关闭健康检查详情,避免把内部组件状态直接暴露给所有调用者。
第 4 步:通过接口观察配置
SystemController 中增加:
@GetMapping("/config")
public ApiResponse<ConfigInfo> config() {
// 把最终生效的配置返回给学习者观察。
return ApiResponse.success(new ConfigInfo(
properties.getLabel(),
properties.getMaxPageSize(),
properties.getRegion(),
environment.getProperty("server.port", "8080")
));
}重新构建:
mvn clean package -DskipTests默认启动:
java -jar demo-web/target/demo-web-1.0.0-SNAPSHOT.jar --server.port=18085请求:
curl "http://localhost:18085/api/v1/system/config"预期数据:
{
"environmentLabel": "dev",
"maxPageSize": 50,
"region": "local",
"port": "18085"
}看到 dev 和 50,说明默认 Profile 和开发配置都已经生效。
第 5 步:切换到生产 Profile
停止服务,重新启动:
java -jar demo-web/target/demo-web-1.0.0-SNAPSHOT.jar \
--server.port=18085 \
--spring.profiles.active=prod再次请求配置接口,预期得到:
{
"environmentLabel": "prod",
"maxPageSize": 20,
"region": "local",
"port": "18085"
}注意,Spring Boot 会加载 application.yml 后再叠加 application-prod.yml。不是只读取 application-prod.yml。
第 6 步:用命令行覆盖单个参数
不修改任何文件,直接启动:
java -jar demo-web/target/demo-web-1.0.0-SNAPSHOT.jar \
--server.port=18085 \
--spring.profiles.active=prod \
--demo.environment.max-page-size=25请求后会看到:
{
"environmentLabel": "prod",
"maxPageSize": 25,
"region": "local",
"port": "18085"
}maxPageSize 变成 25,其他生产配置保持不变。命令行覆盖适合临时验证,不应把长期配置都堆在启动参数里。
第 7 步:用环境变量覆盖区域
macOS 或 Linux:
DEMO_REGION=cn-east \
java -jar demo-web/target/demo-web-1.0.0-SNAPSHOT.jar \
--server.port=18085 \
--spring.profiles.active=prodWindows PowerShell:
$env:DEMO_REGION="cn-east"
java -jar demo-web/target/demo-web-1.0.0-SNAPSHOT.jar --server.port=18085 --spring.profiles.active=prod
Remove-Item Env:DEMO_REGION配置接口应该显示:
{
"environmentLabel": "prod",
"maxPageSize": 20,
"region": "cn-east",
"port": "18085"
}区域没有出现在任何 YAML 的环境差异项中,而是由 ${DEMO_REGION:local} 读取外部变量。
敏感配置应该怎么放?
下面这种写法不要提交到公开仓库:
spring:
# 不要把真实密码提交到 Git。
datasource:
password: my-real-password推荐写:
spring:
# 密码由部署平台通过环境变量注入。
datasource:
password: ${DB_PASSWORD}生产启动时由部署平台注入 DB_PASSWORD。这里不写默认密码,可以让配置缺失时尽早失败。
需要特别记住:
- Git 仓库不存真实密钥。
- 日志不打印密码、Token 和完整连接串。
- Profile 不是权限边界。
- 配置中心也需要认证和审计。
- 修改敏感配置后要重新验证生效来源,而不是只看配置文件。
常见问题排查
| 现象 | 原因 | 处理方式 |
|---|---|---|
| 始终得到 dev 配置 | 启动参数没有传进去 | 检查 --spring.profiles.active |
配置项是 null | 属性名或绑定方法不匹配 | 检查前缀、短横线命名和 getter/setter |
| 环境变量没有生效 | 变量名不符合映射规则或终端未刷新 | 在启动进程前设置并验证 |
| 本地能用、生产缺少配置 | 生产依赖了不存在的默认值 | 让必需项缺失时直接启动失败 |
| 配置值被意外覆盖 | 还有更高优先级来源 | 打印最终配置来源或检查启动参数 |
练习题
增加 demo.environment.featureFlag 配置,并在配置接口中返回。
验收标准:
application-dev.yml和application-prod.yml设置不同值。- 命令行可以覆盖。
- 增加注释说明该配置只用于演示。
- 不把真实商业规则或密码放进公开仓库。
总结
配置管理的重点是“来源明确、覆盖可验证、敏感信息不落库”。通过 Profile、@ConfigurationProperties 和外部变量,同一份构建产物可以适应不同部署环境。
下一篇从配置回到 Spring 容器本身,观察 Bean 从构造、初始化到销毁的完整生命周期。
上一节:自定义 Starter 与自动配置
下一节:Bean 生命周期与依赖注入
13 个企业级实战项目 · 源码 + 教程 + 答疑
简历包装指导AI Agent 实战高并发·微服务Offer 导向持续更新3000+ 同行交流1V1 答疑3 天包退
覆盖高并发、微服务、分布式与 AI Agent:100万QPS短链、企业智能知识库、商城微服务、SaaS点餐、秒杀、刷题小程序、代码生成器、AI Agent 等。券后 ¥129(原价 ¥159),不满意 3 天包退。
