1. 概述
在 Java 开发中,System.getProperty()
和 System.getenv()
都用于获取配置信息,但它们的来源和用途完全不同。
简单来说:
✅ System.getProperty()
读取的是 JVM 级别的系统属性
✅ System.getenv()
读取的是 操作系统级别的环境变量
搞混这两者,容易在部署、配置管理时踩坑。本文将从实战角度讲清楚它们的区别、使用场景以及常见误区。
2. 使用 System.getProperty()
System.getProperty()
用于获取 JVM 的系统属性。这些属性本质上是一个 Properties
对象,包含了 JVM 启动时的配置信息,比如操作系统类型、文件编码、用户目录等。
常见系统属性示例
String osArch = System.getProperty("os.arch");
String osName = System.getProperty("os.name");
String osVersion = System.getProperty("os.version");
String fileSep = System.getProperty("file.separator");
log.info("operating system name: {}", osName);
log.info("operating system arch: {}", osArch);
log.info("Operation System version: {}", osVersion);
log.info("file separator: {}", fileSep);
在 Arch Linux 上运行输出:
[main] INFO com...SystemPropertyAndEnvUnitTest -- operating system name: Linux
[main] INFO com...SystemPropertyAndEnvUnitTest -- operating system arch: amd64
[main] INFO com...SystemPropertyAndEnvUnitTest -- Operation System version: 6.6.34-1-lts
[main] INFO com...SystemPropertyAndEnvUnitTest -- file separator: /
在 macOS(Apple Silicon)上输出:
[main] INFO com...SystemPropertyAndEnvUnitTest -- operating system name: Mac OS X
[main] INFO com...SystemPropertyAndEnvUnitTest -- operating system arch: aarch64
[main] INFO com...SystemPropertyAndEnvUnitTest -- Operation System version: 15.0
[main] INFO com...SystemPropertyAndEnvUnitTest -- file separator: /
⚠️ 注意:
file.separator
在 Windows 是\
,Linux/macOS 是/
,跨平台开发时务必用这个属性,不要硬编码!
查看所有系统属性
System.getProperties().forEach((k, v) -> LOG.info("{} -> {}", k, v));
输出片段:
sun.arch.data.model -> 64
user.timezone -> Europe/Berlin
java.vm.specification.version -> 22
os.name -> Linux
java.class.version -> 66.0
这些属性大部分由 JVM 自动设置,但你也可以自定义。
动态设置系统属性
System.setProperty("nice.tech.site", "Baeldung");
assertEquals("Baeldung", System.getProperty("nice.tech.site"));
✅ 也可以通过启动参数传入:
java -jar app.jar -Dnice.tech.site="Baeldung"
这是生产环境中最常用的配置方式,比如:
java -jar app.jar -Dspring.profiles.active=prod -Dserver.port=8081
✅
System.getProperty()
返回值永远是String
类型,注意空值处理。
3. 使用 System.getenv()
环境变量是操作系统级别的键值对,通常用于配置应用运行环境,比如数据库地址、密钥、PATH 路径等。
它们在 JVM 启动前就已经存在,Java 程序通过 System.getenv()
读取。
获取单个环境变量
String homeDir = System.getenv("HOME");
String shell = System.getenv("SHELL");
String terminal = System.getenv("TERM");
log.info("User Home: {}", homeDir);
log.info("Shell: {}", shell);
log.info("Terminal: {}", terminal);
输出示例:
[main] INFO com...SystemPropertyAndEnvUnitTest -- User Home: /home/kent
[main] INFO com...SystemPropertyAndEnvUnitTest -- Shell: /bin/zsh
[main] INFO com...SystemPropertyAndEnvUnitTest -- Terminal: xterm-256color
获取所有环境变量
System.getenv().forEach((k, v) -> LOG.info("{} -> {}", k, v));
输出片段:
COLORTERM=truecolor
HOME=/home/kent
LC_CTYPE=UTF-8
LOGNAME=U533276
PATH=/home/kent/bin:/usr/bin:...
SHELL=/bin/zsh
PYTHON2_BIN=/home/kent/.pyenv/shims
⚠️ 注意:
System.getenv()
返回的是一个 只读 Map,尝试修改会抛异常:
Map<String, String> sysEnv = System.getenv();
assertThrows(UnsupportedOperationException.class, () -> sysEnv.put("TECH_SITE", "Baeldung"));
如何在运行时设置环境变量?
❌ 直接通过 System.getenv().put()
是行不通的 —— 这是只读的。
但可以通过 ProcessBuilder
为子进程设置环境变量:
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "echo $TECH_SITE");
Map<String, String> env = pb.environment();
env.put("TECH_SITE", "Baeldung");
try (BufferedReader output = new BufferedReader(new InputStreamReader(pb.start().getInputStream()))) {
String result = output.readLine();
log.info("TECH_SITE in the new process: {}", result);
}
log.info("TECH_SITE in the current process: {}", System.getenv("TECH_SITE"));
输出:
[main] INFO com...SystemPropertyAndEnvUnitTest -- TECH_SITE in the new process: Baeldung
[main] INFO com...SystemPropertyAndEnvUnitTest -- TECH_SITE in the current process: null
✅ 结论:
- 环境变量
TECH_SITE
只在子进程中生效 - 当前 JVM 进程无法修改自己的环境变量(除非用反射黑科技,但不推荐)
4. 核心区别总结
特性 | System.getProperty() |
System.getenv() |
---|---|---|
作用域 | JVM 级别 | 操作系统级别 |
来源 | JVM 启动参数(-D )、代码中 System.setProperty() |
系统全局环境变量、shell 脚本、.env 文件等 |
可变性 | ✅ 可在运行时修改 | ❌ 只读(当前进程无法修改) |
典型用途 | JVM 配置、应用 Profile、日志路径等 | 数据库密码、API Key、CI/CD 环境标识等 |
设置方式 | -Dkey=value 启动参数 |
export KEY=VALUE 或系统设置 |
使用建议
- ✅ 配置应用行为?优先用
System.getProperty()
(通过-D
传参) - ✅ 敏感信息(如密码)?用
System.getenv()
,避免出现在进程命令行中 - ✅ 跨平台路径处理?用
System.getProperty("file.separator")
,别硬编码/
或\
- ✅ 部署到 Docker/K8s?环境变量更友好,配合
envFrom
或configMap
5. 总结
System.getProperty()
和 System.getenv()
是 Java 中获取外部配置的两个核心手段:
System.getProperty()
:面向 JVM,灵活可变,适合应用内部配置System.getenv()
:面向操作系统,安全隔离,适合环境敏感信息
理解它们的差异,能帮你写出更健壮、可移植的 Java 应用。尤其是在微服务、容器化部署场景下,合理使用环境变量是最佳实践之一。
💡 小技巧:开发时可以用
.env
文件 + 工具(如dotenv-java
)模拟环境变量,生产环境由运维注入,实现配置解耦。