
System.getProperty 读不到你传的 JVM 参数?先看是不是写错了位置
它只读 JVM 启动时用 -Dkey=value 显式声明的系统属性,不读命令行参数(args)、环境变量(System.getenv())或配置文件。常见错误是把 -D 写成 --D 或漏掉等号,比如 -Dspring.profiles.active=dev 写成 -Dspring.profiles.active dev —— 后者整个键值对会被忽略,System.getProperty("spring.profiles.active") 返回 null。
- 必须用
java -Dkey=value -jar app.jar启动,不能在 IDE 的 “Program arguments” 栏里填(那是传给main(String[] args)的) - IDE 中需在 “VM options” 或 “Run Configuration → VM Options” 里设置
-D参数 - Spring Boot 应用里,
-D属性默认会转为 Spring Environment 的 property,但System.getProperty()仍只认原始 JVM 层面的-D
哪些 key 是内置的?别硬记,运行时查最准
System.getProperty() 能读的 key 分两类:JVM 自带的(如 "os.name"、"java.version")和用户用 -D 注入的。JVM 规范没强制要求所有 key 兼容,不同 JDK 版本返回值可能有细微差异(比如 "file.separator" 在 Windows 是 "\",Linux 是 "/"),但核心 key 稳定。别依赖 "user.dir" 做绝对路径拼接——它返回的是启动目录,不是 jar 包所在目录。
- 常用内置 key:
"os.name"、"os.arch"、"java.home"、"user.home"、"line.separator" - 获取所有当前可用属性:
System.getProperties().list(System.out)(调试用,别上线) -
"sun.java.command"可读到完整启动命令(含 main class 和 args),但非标准属性,OpenJDK 17+ 默认禁用,需加--add-opens java.base/java.lang=ALL-UNNAMED
空值判断不加防护?线上直接 NPE
System.getProperty() 永远不会抛异常,但返回 null 很常见:参数没传、拼写错误、大小写不一致("MyKey" ≠ "mykey")。直接链式调用或未判空就 .equals(),100% 触发 NullPointerException。
- 安全写法:
Objects.equals(System.getProperty("env"), "prod")或"prod".equals(System.getProperty("env")) - 提供默认值:
System.getProperty("timeout", "3000")—— 第二个参数是 fallback 字符串,仅当 key 不存在或值为null时生效 - 避免用
Boolean.parseBoolean(System.getProperty("debug")):若值是"false"也返回false,但若 key 不存在则返回false,无法区分“明确关”和“没配”
和 System.getenv() 混用?注意优先级和覆盖逻辑
环境变量(System.getenv())和 JVM 属性(System.getProperty())完全独立,无自动同步。有些框架(如 Spring Boot)会按顺序合并:JVM 属性 > 环境变量 > 配置文件。但纯 Java 程序里,二者就是两套平行系统。常见陷阱是本地用 export MY_ENV=dev 测试,却忘了加 -DMY_ENV=dev,结果 System.getProperty("MY_ENV") 还是 null。
立即学习“Java免费学习笔记(深入)”;
- 环境变量名通常全大写 + 下划线(
DB_HOST),JVM 属性习惯用点分小写(db.host),别强行统一命名风格 - Docker 容器中,
-e DB_HOST=xxx设置的是环境变量,要让System.getProperty("db.host")生效,得额外加-Ddb.host=$DB_HOST(在 entrypoint 脚本里展开) - 敏感信息(密码、密钥)别走
-D,进程列表可见;优先用环境变量 + 读取时擦除,或挂载文件
真正麻烦的是跨层级覆盖:Kubernetes ConfigMap 注入环境变量,应用又用 -D 覆盖部分值,再被代码里硬编码 fallback 打断——这种链路一旦出问题,排查时得一层层确认每个环节的输入源。










