首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 系統屬性獲取與屬性文件操作全攻略:跨平台配置管理實戰

     編輯:Java 相關知識

前言:為什麼需要系統屬性?

Java 「一次編寫,到處運行」的承諾建立在屏蔽平台差異之上。但應用往往需要知道:當前是 Windows 還是 Linux?用戶主目錄在哪?JDK 安裝路徑?工作目錄?java.util.Properties 與 System.getProperties() 正是通往這些運行時環境信息的標準接口。本文系統梳理系統屬性獲取、自定義屬性文件操作、安全策略配置,並給出生產級最佳實踐。

一、核心系統屬性速查表

屬性鍵含義Windows 示例Linux 示例
file.separator文件分隔符\/
path.separator路徑分隔符;:
user.home用戶主目錄C:\Users\name/home/name
user.dir當前工作目錄D:\project/opt/app
java.homeJRE 安裝目錄C:\Java\jre1.8/usr/lib/jvm/java-8
java.versionJava 版本1.8.0_20211.0.12
os.name操作系統名稱Windows 10Linux
os.archCPU 架構amd64aarch64
line.separator行分隔符\r\n\n

獲取所有屬性:System.getProperties().list(System.out);

二、Properties 核心 API 速覽

讀取操作


Properties props = System.getProperties(); // 系統屬性
// 或
Properties props = new Properties();
props.load(new FileInputStream("config.properties")); // 文件屬性

// 獲取值
String value = props.getProperty("key");           // 無則返回 null
String value = props.getProperty("key", "default"); // 無則返回默認值

// 檢查存在性
boolean hasKey = props.containsKey("key");
boolean hasValue = props.contains("value"); // 注意:查找值而非鍵

// 遍歷
props.forEach((k, v) -> System.out.println(k + "=" + v));
props.stringPropertyNames().forEach(k -> System.out.println(k + "=" + props.getProperty(k)));

// 輸出調試
props.list(System.out); // 打印到 PrintStream
props.list(new PrintWriter(System.out)); // 打印到 PrintWriter

寫入操作


props.setProperty("key", "value"); // 僅 String,推薦
props.put("key", "value");         // 繼承自 Hashtable,接受 Object

// 移除
props.remove("key"); // 返回舊值

// 保存到文件(需輸出流)
props.store(new FileOutputStream("config.properties"), "配置文件註釋");
// XML 格式保存(JDK 1.5+)
props.storeToXML(new FileOutputStream("config.xml"), "XML 註釋", "UTF-8");

三、自定義屬性文件:外部化配置最佳實踐

1. 標準加載模式


public class ConfigManager {
    private static final Properties PROPS = new Properties();
    private static final String CONFIG_FILE = "app.properties";
    
    static {
        load();
    }
    
    private static void load() {
        try (InputStream in = ConfigManager.class.getClassLoader()
                .getResourceAsStream(CONFIG_FILE)) {
            if (in != null) {
                PROPS.load(in);
            } else {
                // 回退到文件系統
                try (FileInputStream fin = new FileInputStream(CONFIG_FILE)) {
                    PROPS.load(fin);
                } catch (FileNotFoundException ignored) {
                    // 使用默認值
                }
            }
        } catch (IOException e) {
            throw new ExceptionInInitializerError("配置加載失敗: " + e.getMessage());
        }
    }
    
    public static String get(String key) { return PROPS.getProperty(key); }
    public static String get(String key, String def) { return PROPS.getProperty(key, def); }
    public static int getInt(String key, int def) { 
        return Integer.parseInt(PROPS.getProperty(key, String.valueOf(def))); 
    }
    
    // 運行時動態修改並持久化
    public static void setAndSave(String key, String value) {
        PROPS.setProperty(key, value);
        try (FileOutputStream out = new FileOutputStream(CONFIG_FILE)) {
            PROPS.store(out, "Updated at " + Instant.now());
        } catch (IOException e) {
            log.error("配置保存失敗", e);
        }
    }
}

2. 屬性文件示例


# app.properties
# 數據庫配置
db.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
db.username=app_user
db.password=encrypted:xxx
db.pool.size=20

# 功能開關
feature.new-ui.enabled=true
feature.cache.ttl.seconds=3600

# 路徑配置(使用系統屬性佔位符,需自行解析)
upload.dir=${user.home}/uploads
log.dir=${user.dir}/logs

四、安全策略文件:精細權限控制

Java 安全架構基於 Policy 對象,通過策略文件授予代碼特定權限。三級策略加載順序:

  1. 系統策略:${java.home}/conf/security/java.policy(JDK 9+)或 lib/security/java.policy
  2. 用戶策略:${user.home}/.java.policy
  3. 應用指定:-Djava.security.policy=app.policy

策略文件語法


/* app.policy */
grant codeBase "file:/opt/myapp/-" {
    // 文件讀寫權限
    permission java.io.FilePermission "/opt/myapp/data/-", "read,write";
    permission java.io.FilePermission "/tmp/-", "read,write,delete";
    
    // 網絡連接權限
    permission java.net.SocketPermission "db.internal:3306", "connect,resolve";
    permission java.net.SocketPermission "api.external.com:443", "connect,resolve";
    
    // 系統屬性讀取權限
    permission java.util.PropertyPermission "app.config.*", "read";
    
    // 反射訪問權限
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};

// 特定簽名代碼授予更高權限
grant signedBy "mycompany" {
    permission java.security.AllPermission;
};

啟用安全管理器(JDK 17 前)


// 命令行啟動
java -Djava.security.manager -Djava.security.policy=app.policy -jar app.jar

// 代碼中啟用(main 方法最早)
System.setSecurityManager(new SecurityManager());

注意:JDK 17 起 SecurityManager 被棄用,建議遷移到容器級隔離、模塊系統強封裝、OS 級沙箱。

五、生產環境配置管理進階模式

1. 分層配置覆蓋


// 優先級:默認值 < application.properties < profile.properties < 環境變量 < 命令行參數
Properties loadLayeredConfig() {
    Properties props = new Properties();
    // 1. 默認配置(打包在 jar 內)
    props.load(getClass().getResourceAsStream("/default.properties"));
    // 2. 應用配置(部署目錄)
    loadIfExists(props, "config/application.properties");
    // 3. 環境配置(如 prod.properties)
    String profile = System.getProperty("spring.profiles.active", "dev");
    loadIfExists(props, "config/" + profile + ".properties");
    // 4. 環境變量覆蓋(自動映射 DB_URL → db.url)
    System.getenv().forEach((k, v) -> {
        String propKey = k.toLowerCase().replace('_', '.');
        props.setProperty(propKey, v);
    });
    // 5. 命令行參數 -Dxxx=yyy
    System.getProperties().forEach((k, v) -> props.setProperty((String)k, (String)v));
    return props;
}

2. 敏感信息加密存儲


// 加密工具類(簡化示例,生產用 Jasypt/Vault)
public class CryptoConfig {
    private static final String PREFIX = "ENC(";
    
    public static String decryptIfNeeded(String value) {
        if (value != null && value.startsWith(PREFIX) && value.endsWith(")")) {
            String encrypted = value.substring(PREFIX.length(), value.length() - 1);
            return AESUtil.decrypt(encrypted, getMasterKey());
        }
        return value;
    }
    
    // 包裝 Properties.getProperty
    public static String getProperty(Properties props, String key) {
        return decryptIfNeeded(props.getProperty(key));
    }
}

六、總結與檢查清單

場景推薦方案關鍵點
獲取運行環境信息System.getProperty(key)跨平台路徑用 File.separator、File.pathSeparator
應用業務配置Properties 文件 + 分層覆蓋類加載器優先、環境變量覆蓋、敏感信息加密
用戶偏好設置Preferences API自動跨平台持久化、無需管理文件路徑
安全權限控制Policy 文件 + SecurityManager(舊版本)最小權限原則、基於 codeBase/signedBy 授權
現代雲原生配置Spring Cloud Config / Consul / etcd / Kubernetes ConfigMap動態刷新、版本控制、集中管理

掌握 Properties 與系統屬性,是 Java 開發者處理「環境感知」與「外部化配置」的基本功。從單機屬性文件到分布式配置中心,核心原理始終是:**配置與代碼分離、環境差異外部化、敏感信息加密、變更可追蹤**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved