核心概念區分
| 維度 | 環境變量 | 系統屬性 |
| 來源 | 操作系統級(Windows 注冊表、Linux /etc/profile) | JVM 運行時內部維護 |
| 作用域 | 進程及其子進程可見(全局) | 僅當前 JVM 進程可見 |
| 大小寫 | Windows 不敏感,Linux 敏感 | 嚴格區分大小寫 |
| 典型用途 | PATH、JAVA_HOME、DATABASE_URL | java.version、file.encoding、user.dir |
| API | System.getenv() | System.getProperty() |
環境變量操作
// 獲取所有環境變量(Map,不可修改)
Map env = System.getenv();
env.forEach((k, v) -> System.out.println(k + "=" + v));
// 獲取單個(推薦)
String javaHome = System.getenv("JAVA_HOME");
String path = System.getenv("PATH");
// ⚠️ Java 無法直接修改進程環境變量
// 僅能在創建子進程時指定:
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "echo %JAVA_HOME%");
pb.environment().put("MY_VAR", "custom_value");
Process process = pb.start();
系統屬性操作
// 獲取所有(Properties 對象,可修改)
Properties props = System.getProperties();
props.forEach((k, v) -> System.out.println(k + "=" + v));
// 獲取單個(支持默認值)
String version = System.getProperty("java.version");
String encoding = System.getProperty("file.encoding", "UTF-8"); // 默認值
// 設置系統屬性(僅影響當前 JVM)
System.setProperty("my.app.config", "/opt/config");
System.setProperty("log.level", "DEBUG");
// 命令行啟動時指定(推薦配置方式)
// java -Dfile.encoding=UTF-8 -Dmy.config=/path -jar app.jar
常用系統屬性速查表
| 屬性名 | 含義 | 示例值 |
| java.version | JRE 版本 | 17.0.9 |
| java.home | JRE 安裝目錄 | /usr/lib/jvm/java-17-openjdk |
| java.class.path | 類路徑 | .:/app/lib/* |
| java.library.path | 原生庫搜索路徑 | /usr/lib |
| java.io.tmpdir | 臨時文件目錄 | /tmp |
| os.name | 操作系統名稱 | Linux / Windows 10 |
| os.arch | OS 架構 | amd64 / aarch64 |
| file.separator | 文件分隔符 | / 或 \ |
| path.separator | 路徑分隔符 | : 或 ; |
| line.separator | 行分隔符 | \n 或 \r\n |
| user.name | 當前用戶名 | admin |
| user.home | 用戶主目錄 | /home/admin |
| user.dir | 工作目錄 | /app |
實戰最佳實踐
1. 配置優先級鏈(Spring Boot 風格)
// 1. 默認值(代碼內)
// 2. 系統屬性 -Dxxx
// 3. 環境變量 XXX_YYY
// 4. 配置文件 application.yml
// 5. 命令行參數 --xxx=yyy
String value = System.getProperty("app.config");
if (value == null) value = System.getenv("APP_CONFIG");
if (value == null) value = "default";
2. 容器化部署規範
- 敏感配置(密碼、密鑰)只用環境變量,掛載 Secret
- 應用行為配置(日誌級別、線程池大小)用系統屬性
-D
- Dockerfile 中
ENV JAVA_OPTS="-Dfile.encoding=UTF-8 -Xms512m -Xmx1g"
3. 安全管理器影響
// 受 SecurityManager 限制時會拋出 AccessControlException
System.setSecurityManager(new SecurityManager());
System.getProperties(); // 拋出異常:checkPropertiesAccess
// 解決:授權 policy 文件或移除 SecurityManager(現代框架多不使用)
4. log4j2 / Logback 變量替換
<!-- log4j2.xml -->
<Property name="LOG_DIR">${sys:user.home}/logs</Property> <!-- 系統屬性 -->
<Property name="LOG_DIR">${env:LOG_DIR}</Property> <!-- 環境變量 -->
<Appender type="RollingFile" fileName="${LOG_DIR}/app.log"/>
總結
- 環境變量:跨進程、跨語言、部署層面配置,只讀
- 系統屬性:JVM 內部運行參數,可讀寫,啟動時
-D 指定最佳
- 配置獲取遵循優先級鏈,代碼中提供合理默認值
- 容器化場景嚴格區分敏感/非敏感配置存儲方式
清晰區分兩者邊界,是構建可移植、可配置、安全的 Java 應用基石。