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

Java 讀取 Properties 配置文件三種姿勢:從入門到最佳實踐

     編輯:Java 相關知識

場景

項目中常需讀取 db.properties、config.properties 等配置文件,獲取數據庫連接參數、業務開關等。關鍵難點:**路徑定位穩健**、**配置緩存熱加載**、**線程安全**。

方案演進

階段一:硬編碼絕對/相對路徑(不推薦)

FileInputStream fis = new FileInputStream("D:/project/config/db.properties"); // 絕對路徑
// 或
FileInputStream fis = new FileInputStream("src/db.properties"); // 相對路徑,部署後失效

痛點:遷移環境需改代碼,打包後路徑失效,維護成本極高。

階段二:ClassLoader 獲取資源流(非靜態場景可用)

public class ConfigLoader {
    private Properties props = new Properties();
    public ConfigLoader() {
        try (InputStream is = getClass().getResourceAsStream("/db.properties")) {
            props.load(is);
        } catch (IOException e) { throw new RuntimeException(e); }
    }
    public String get(String key) { return props.getProperty(key); }
}

優點:無需關心物理路徑,打包進 JAR 同級目錄即可訪問。
缺點:構造器中初始化,無法實現靜態緩存;每次 new 都會重複讀取 IO。

階段三:靜態塊 + 類加載器(推薦生產模式)

public final class DbConfig {
    private static String URL;
    private static String USER;
    private static String PASS;

    static {
        load();
    }

    private static synchronized void load() {
        if (URL != null) return; // 雙重檢查
        try (InputStream is = DbConfig.class.getResourceAsStream("/db.properties")) {
            Properties props = new Properties();
            props.load(is);
            URL = props.getProperty("jdbc.url");
            USER = props.getProperty("jdbc.user");
            PASS = props.getProperty("jdbc.password");
        } catch (IOException e) {
            throw new ExceptionInInitializerError("配置文件加載失敗: " + e.getMessage());
        }
    }

    public static String getUrl() { return URL; }
    public static String getUser() { return USER; }
    public static String getPass() { return PASS; }
}

亮點:

  • 類加載時自動初始化,調用方無感知;
  • 靜態字段緩存,避免重複 IO;
  • synchronized 保證多線程環境下單次加載;
  • 拋出 ExceptionInInitializerError 快速失敗,暴露配置缺失。

進階:支援熱加載(可選)

public class ReloadableConfig {
    private static final AtomicReference<Properties> REF = new AtomicReference<>();
    private static final ScheduledExecutorService SCHEDULER = Executors.newSingleThreadScheduledExecutor();

    static {
        reload();
        SCHEDULER.scheduleAtFixedRate(ReloadableConfig::reload, 1, 1, TimeUnit.MINUTES);
    }

    private static void reload() {
        try (InputStream is = ReloadableConfig.class.getResourceAsStream("/config.properties")) {
            Properties props = new Properties();
            props.load(is);
            REF.set(props);
        } catch (IOException e) {
            log.error("配置熱加載失敗", e);
        }
    }

    public static String get(String key) {
        return REF.get().getProperty(key);
    }
}

避坑指南

  • getResourceAsStream("/xxx.properties"):前導斜杠表示 classpath 根目錄(即 src/main/resources),無斜杠則相對當前類包路徑。
  • 多模塊項目中,配置文件置於各模塊 resources,或統一放在獨立 config-module 依賴引入。
  • 敏感信息(密碼、AK/SK)**嚴禁**寫入 properties 入倉庫,應用環境變量/配置中心/密管平台注入。

總結

「靜態塊 + ClassLoader + 雙重檢查鎖」是讀取 classpath 配置的工業級標準寫法,兼顧性能、線程安全、部署無關性。若需動態刷新,引入定時任務 + AtomicReference 即可平滑擴展。

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