Properties 是 Java 自带最轻量配置方案,需用 UTF-8 Reader/Writer 避免中文乱码;建议封装 Config 类安全转换类型;热更新应校验文件修改时间并线程安全替换;集合配置用分号分隔,避免 JSON。

用 Properties 读写配置文件最直接
Java 自带的 java.util.Properties 是处理键值对配置文件(如 app.properties)最轻量、最稳妥的选择,无需引入第三方依赖,且天然支持 ISO-8859-1 编码(中文需显式指定 UTF-8)。
常见错误是直接用 load(InputStream) 读取含中文的文件,结果乱码——因为默认按 ISO-8859-1 解析。正确做法是用 load(Reader) 并传入 UTF-8 InputStreamReader:
Properties props = new Properties();
try (InputStream is = getClass().getResourceAsStream("/config/app.properties");
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
props.load(reader);
}
写入时同理,用 store(Writer, comment) 替代 store(OutputStream, comment),避免写入后中文变成问号。
把配置映射到 Java 对象要用 Configuration 或手动封装
纯 Properties 只提供字符串键值,无法自动转成 int、boolean 或嵌套结构。如果项目稍复杂(比如有数据库连接池参数),建议封装一层:
立即学习“Java免费学习笔记(深入)”;
- 定义一个
Config类,字段对应配置项,加 getter; - 构造时传入
Properties,在内部用getProperty("key", "default")安全读取; - 数值类型用
Integer.parseInt()或Boolean.parseBoolean()转换,并捕获NumberFormatException做降级处理。
不推荐直接用反射或通用 BeanUtils 自动填充——配置缺失或类型错配时失败位置难定位,反而增加调试成本。
配置热更新不能靠 Properties::load 简单重载
很多开发者以为“每次读配置前重新 load 一次文件”就算热更新,但这样存在两个问题:
- 文件未修改时重复 IO,浪费资源;
- 多线程并发读写时,可能读到半截内容(
Properties不是线程安全的)。
可行方案是:用 Files.getLastModifiedTime(path) 检查时间戳变化,仅当变更后才重建 Properties 实例,并用 volatile 字段或 AtomicReference 替换旧实例。更稳妥的做法是加一层简单锁(如 synchronized 块)保护加载过程。
集合类配置项要约定分隔符,别硬解析 JSON
如果需要配置“允许的 IP 列表”或“日志级别白名单”,不要在 .properties 里写 JSON 字符串(如 allowed_ips=[\"127.0.0.1\",\"192.168.1.0/24\"])。JSON 解析依赖额外库,且易因格式错误导致整个配置加载失败。
统一用简单分隔符,比如逗号或分号:
allowed_ips=127.0.0.1;192.168.1.0/24;10.0.0.0/8
读取后用 String.split(";") 得到 String[],再 Arrays.asList() 转为 List。注意 trim 每个元素,防止空格干扰。
路径、URL、正则等含特殊字符的值,用双引号包裹并手动去引号,比强行兼容 JSON 更可控。










