Properties 文件是 Java 專案最常見的配置載體。但根據配置文件位置(類路徑、檔案系統、JAR 內部、War 內部)、訪問上下文(普通類、Servlet、Spring 容器),最佳讀取方式不同。本文系統梳理 6 種核心 API 用法與 1 個 Servlet 擴展,附帶適用場景對照表。
| # | API | 適用場景 | 關鍵特點 |
|---|---|---|---|
| 1 | Properties.load(InputStream) | 檔案系統絕對/相對路徑 | 最基礎,需自行管理流關閉 |
| 2 | ResourceBundle.getBundle(baseName) | 類路徑下 .properties 文件(無副檔名) | 支援 Locale 變體、緩存機制、不可熱重載 |
| 3 | new PropertyResourceBundle(InputStream) | 需手動控制流來源的 ResourceBundle | 可讀取任意 InputStream 來源 |
| 4 | Class.getResourceAsStream(path) | 相對於當前類的類路徑資源 | 路徑不以 / 開頭 = 相對路徑 |
| 5 | Class.getClassLoader().getResourceAsStream(path) | 類路徑根目錄下的資源 | 路徑不以 / 開頭 = 絕對路徑(從 classpath root) |
| 6 | ClassLoader.getSystemResourceAsStream(path) | 系統類加載器可見資源(啟動類路徑) | 不受自定義類加載器影響 |
public final class PropsUtil {
private PropsUtil() {}
/** 從類路徑讀取(最常用) */
public static Properties loadFromClasspath(String path) {
try (InputStream in = PropsUtil.class.getClassLoader().getResourceAsStream(path)) {
if (in == null) throw new IllegalArgumentException("Resource not found: " + path);
Properties props = new Properties();
props.load(in);
return props;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/** 從檔案系統讀取 */
public static Properties loadFromFile(String filePath) {
try (InputStream in = new BufferedInputStream(new FileInputStream(filePath))) {
Properties props = new Properties();
props.load(in);
return props;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/** 從 ServletContext 讀取(Web 環境) */
public static Properties loadFromServletContext(ServletContext ctx, String path) {
try (InputStream in = ctx.getResourceAsStream(path)) {
if (in == null) throw new IllegalArgumentException("Resource not found: " + path);
Properties props = new Properties();
props.load(in);
return props;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
// 假設類結構:com.example.MyClass,resources/config.properties
MyClass.class.getResourceAsStream("config.properties") // → com/example/config.properties (相對)
MyClass.class.getResourceAsStream("/config.properties") // → config.properties (絕對,從 classpath root)
MyClass.class.getClassLoader().getResourceAsStream("config.properties") // → config.properties (絕對,從 classpath root)
規則:Class 方法支援相對路徑;ClassLoader 方法永遠視為絕對路徑(相對 classpath root),不可以 / 開頭。
ResourceBundle.getBundle() 預設緩存永久,修改 .properties 文件不生效。解決方案:
ResourceBundle.Control 自定義緩存策略(JDK 9+ 推薦)Properties.load() 配合文件監聽實現熱重載若專案使用 Spring,請勿手寫上述代碼,直接使用:
@PropertySource("classpath:config.properties") + Environment@Value("${key}") / @ConfigurationProperties 綁定PropertySourcesPlaceholderConfigurer 解析 ${...} 佔位符application.properties/yml 自動載入,@ConfigurationProperties 類型安全綁定ClassLoader.getResourceAsStream() 讀取 classpath 資源ServletContext.getResourceAsStream() 讀取 /WEB-INF/classes/ 或 /WEB-INF/ 下配置ResourceBundle 機制Properties + 文件監聽 / Apache Commons Configuration / Spring Cloud Config