數據庫連接參數、第三方服務密鑰、功能開關等不應硬編碼,通過 .properties 文件外部化,運行時動態加載。
src/
└── main/
├── java/
│ └── com/example/config/
│ └── ConfigLoader.java
└── resources/
└── application.properties
jdbc.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=secret123
app.feature.cache.enabled=true
app.max.connections=20
package com.example.config;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ConfigLoader {
private static final Properties PROPS = new Properties();
static {
// 1. 通過類加載器獲取資源流(classpath 根目錄)
try (InputStream in = ConfigLoader.class.getClassLoader()
.getResourceAsStream("application.properties")) {
if (in == null) {
throw new IllegalStateException("找不到 application.properties");
}
PROPS.load(in);
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
public static String get(String key) {
return PROPS.getProperty(key);
}
public static String get(String key, String defaultValue) {
return PROPS.getProperty(key, defaultValue);
}
public static int getInt(String key, int defaultValue) {
String val = PROPS.getProperty(key);
return val != null ? Integer.parseInt(val.trim()) : defaultValue;
}
// 測試
public static void main(String[] args) {
System.out.println("URL: " + get("jdbc.url"));
System.out.println("Driver: " + get("jdbc.driver"));
System.out.println("Cache: " + get("app.feature.cache.enabled"));
}
}
getClassLoader().getResourceAsStream():從 classpath 根路徑加載,不加前導斜槓ClassName.class.getResourceAsStream("/path"):從 classpath 根路徑加載,需加前導斜槓package com.example.config;
import java.util.ResourceBundle;
public class ConfigLoaderRB {
private static final ResourceBundle BUNDLE =
ResourceBundle.getBundle("application"); // 不加 .properties,不加路徑
public static String get(String key) {
return BUNDLE.getString(key); // 找不到拋 MissingResourceException
}
public static String getOrDefault(String key, String defaultValue) {
try { return BUNDLE.getString(key); }
catch (Exception e) { return defaultValue; }
}
public static void main(String[] args) {
System.out.println("URL: " + get("jdbc.url"));
System.out.println("Driver: " + get("jdbc.driver"));
}
}
| 特性 | 說明 |
|---|---|
| 基於鍵值查找 | getString(key),無 getProperty 類似方法 |
| 缓存機制 | JVM 緩存 Bundle 實例,修改文件需重啟或手動清理緩存 |
| 國際化支持 | 自動查找 application_zh_CN.properties 等本地化文件 |
| 編碼要求 | ISO-8859-1,中文需用 native2ascii 轉義或 JDK 9+ 用 UTF-8 |
| 異常行為 | 鍵不存在拋 MissingResourceException(Properties 返回 null) |
| 維度 | Properties + ClassLoader | ResourceBundle |
|---|---|---|
| 適用場景 | 通用配置、數據庫連接、功能開關 | 國際化文本、多語言資源 |
| 編碼靈活性 | UTF-8 直接支持 | 歷史包袱,需注意編碼 |
| 鍵缺失處理 | 返回 null,可提供默認值 | 拋異常,需 try-catch |
| 熱加載支持 | 易結合 WatchService 實現 | 緩存機制較難熱加載 |
| 推薦度 | ⭐⭐⭐⭐⭐ | ⭐⭐ (非 i18n 場景) |
實際項目中極少手寫加載代碼,直接用 Spring 注解:
@Configuration
@ConfigurationProperties(prefix = "jdbc")
public class JdbcConfig {
private String url;
private String driver;
private String username;
private String password;
// getter/setter
}
// 或單值注入
@Service
public class MyService {
@Value("${app.max.connections:10}")
private int maxConnections;
}
src/main/resources,打包進 JAR 根目錄,ClassLoader 即可訪問