一、问题背景
在 Spring Boot 项目里,配置文件用占位符引用环境变量可以说是家常便饭了,比如下面这种写法:

url: jdbc:mysql://${datasource_addr:10.xxx.xxx.xxx:5236}/mydb
但有一个现象挺让人头疼的:同样的配置,在 IDEA 里跑得好好的,一到 Docker 的 Linux 环境下就翻车了,环境变量死活读不到。
这篇文章就来拆解一下这个问题的根源,顺便把 IDEA 里 Spring Boot 的启动配置参数也捋一捋,希望能帮大家少走些弯路。
1.1 环境
- jdk 17
- springboot 3.4
二、问题分析
2.1 现象描述
| 环境 | 配置方式 | 结果 |
|---|---|---|
| IDEA | 进程传参(Program Arguments) | ✅ 正常读取 |
| Docker Linux | 系统环境变量(-e 参数) | ❌ 读取失败 |
2.2 根本原因
1. Spring Boot RelaxedBinding 机制
Spring Boot 内置了一个所谓的“宽松绑定”机制,允许属性名以多种形式相互映射,比如:
datasource_addr → datasource.addr → DATASOURCE_ADDR → datasource-addr
但这个机制在各个阶段的表现并不完全一致:
| 阶段 | RelaxedBinding 状态 | 说明 |
|---|---|---|
| 启动初期 | 完全生效 | spring.profiles.active 等核心属性 |
| Bean 初始化阶段 | 部分生效 | 数据源等组件初始化时 |
2. Linux 环境变量大小写敏感
- Windows:环境变量不区分大小写,
profile和PROFILE是等价的。 - Linux:环境变量严格区分大小写,
profile和PROFILE完全是两个不同的变量。
3. 为什么${profile}可以工作?
spring:
profiles.active: ${profile:default}
profile这个变量在 Spring Boot 启动的最早期就被解析了。- 此时,宽松绑定机制完全生效,Spring 会自动尝试
PROFILE、profile等多种形式,所以能顺利匹配上。
4. 为什么${datasource_addr}可能失败?
url: jdbc:mysql://${datasource_addr:10.xxx.xxx.xxx:5236}/mydb
datasource_addr是在数据源初始化阶段才被解析的。- 此时,宽松绑定机制可能还没有完全就位,尤其是对下划线
_的处理,在不同环境下会有差异。 - 在 Linux 环境下,必须使用大写形式
DATASOURCE_ADDR才能正确匹配。
三、IDEA Spring Boot 启动配置详解
在 IDEA 里运行 Spring Boot 应用时,可以通过以下几种方式传参,每种方式的作用域和优先级都不同:
3.1 Active Profiles(激活配置文件)
用途:指定激活的 Spring Profile。
配置方式:
- 在 Run/Debug Configurations 中设置
Active profiles。 - 多个 profile 用逗号分隔。
等效参数:
--spring.profiles.active=dev,test
示例:
Active profiles: xprd
3.2 Environment Variables(环境变量)
用途:设置进程级别的环境变量。
配置方式:
- 在 Run/Debug Configurations 中设置
Environment variables。 - 格式:
KEY=VALUE,多个用分号分隔。
示例:
DATASOURCE_ADDR=10.xxx.xxx.xxx:5236 PROFILE=xprd
特点:
- 在所有操作系统上行为一致。
- Spring Boot 会自动读取。
- 宽松绑定机制完全生效。
3.3 VM Options(虚拟机参数)
用途:传递 JVM 参数或系统属性。
配置方式:
- 在 Run/Debug Configurations 中设置
VM options。 - 系统属性格式:
-Dproperty=value。
示例:
-Dspring.profiles.active=xprd -Ddatasource_addr=10.xxx.xxx.xxx:5236 -Xms512m -Xmx1024m
特点:
- 通过
System.getProperty()获取。 - 优先级高于环境变量。
- 适合传递 JVM 配置参数。
3.4 Program Arguments(程序参数)
用途:传递命令行参数。
配置方式:
- 在 Run/Debug Configurations 中设置
Program arguments。 - 格式:
--key=value或key=value。
示例:
--spring.profiles.active=xprd --datasource_addr=10.xxx.xxx.xxx:5236
特点:
- Spring Boot 自动解析
--key=value格式。 - 优先级最高。
- 适合覆盖配置文件中的属性。
3.5 参数优先级顺序
从高到低:
- Program Arguments(程序参数)
- VM Options(系统属性)
- Environment Variables(环境变量)
- application-{profile}.yml(配置文件)
- application.yml(默认配置)
四、Docker 部署最佳实践
4.1 环境变量命名规范
推荐做法:使用大写字母 + 下划线。
# ✅ 推荐 DATASOURCE_ADDR=10.xxx.xxx.xxx:5236 SPRING_PROFILES_ACTIVE=xprd # ❌ 不推荐 datasource_addr=10.xxx.xxx.xxx:5236 spring.profiles.active=xprd
4.2 Docker 环境变量传递方式
方式一:docker run -e 参数
docker run -d --name myapp -e DATASOURCE_ADDR=10.xxx.xxx.xxx:5236 -e SPRING_PROFILES_ACTIVE=xprd myimage:latest
方式二:docker-compose.yml
version: '3.8'
services:
myapp:
image: myimage:latest
environment:
- DATASOURCE_ADDR=10.xxx.xxx.xxx:5236
- SPRING_PROFILES_ACTIVE=xprd
方式三:env_file
# .env 文件 DATASOURCE_ADDR=10.xxx.xxx.xxx:5236 SPRING_PROFILES_ACTIVE=xprd
# docker-compose.yml
version: '3.8'
services:
myapp:
image: myimage:latest
env_file:
- .env
方式四:CMD 参数传递
# Dockerfile ENTRYPOINT ["ja va", "-jar", "app.jar"] CMD ["--spring.profiles.active=xprd"]
docker run myimage:latest --datasource_addr=10.xxx.xxx.xxx:5236
4.3 配置文件最佳实践
推荐配置:
spring:
datasource:
url: jdbc:mysql://${DATASOURCE_ADDR:10.xxx.xxx.xxx:5236}/mydb
profiles:
active: ${SPRING_PROFILES_ACTIVE:default}
说明:
- 占位符使用大写形式
${DATASOURCE_ADDR}。 - 保留默认值作为兜底。
- 与 Linux 环境变量命名规范保持一致。
五、问题排查清单
遇到环境变量读取问题时,可以按这个顺序来排查:
检查环境变量是否正确设置
# 在容器内执行 env | grep DATASOURCE
检查环境变量大小写
# Linux 区分大小写 echo $DATASOURCE_ADDR # 正确 echo $datasource_addr # 可能为空
检查 Spring Boot 启动日志
# 查看实际加载的配置 DEBUG=true ja va -jar app.jar
验证配置文件占位符
# 确保占位符格式正确 ${VARIABLE_NAME:default_value}检查 Dockerfile ENTRYPOINT/CMD
# 确保 ENTRYPOINT 使用 exec 形式 ENTRYPOINT ["ja va", "-jar", "app.jar"]
六、总结
| 场景 | 推荐做法 |
|---|---|
| IDEA 开发 | 使用 Environment Variables 或 Program Arguments |
| Docker 部署 | 使用大写环境变量名 + 下划线分隔 |
| 配置文件 | 占位符使用大写形式,保留默认值 |
| 多环境配置 | 通过 SPRING_PROFILES_ACTIVE 切换 |
核心原则:
- 环境变量命名统一使用大写 + 下划线。
- 配置文件占位符与环境变量名保持一致。
- 始终提供默认值作为兜底。
- 充分理解 Spring Boot 属性绑定机制在不同阶段的表现差异。