Java Properties类深度解析:从入门到精通,轻松读写配置文件
目录导读
- 核心概念:Properties类是什么?
- 基础操作:如何创建与加载配置文件
- 读写实战:Properties的CRUD操作详解
- 高级技巧:中文乱码处理与默认值机制
- 常见问答:面试官最常问的3个问题
- 最佳实践:企业级配置文件管理策略
核心概念:Properties类是什么?
java.util.Properties 是Java标准库中专门用于处理配置文件的工具类,它继承自 Hashtable,以键值对的形式存储配置数据,并提供持久化到文件的能力,在实际开发中,我们通常用它来读写 .properties 格式的配置文件。

特性速览
- 基于Key-Value存储:每个配置项由键和值组成,用等号()或冒号()分隔。
- 继承自Hashtable:因此具备线程安全特性,但注意
Properties的store和load方法本身并不是原子操作。 - 支持默认值:通过构造函数或
getProperty(key, defaultValue)提供回退机制。 - 默认编码兼容:但需注意中文存储时可能因编码问题导致乱码。
典型使用场景
- 数据库连接配置(JDBC URL、用户名、密码)
- 系统运行参数(日志级别、端口号、缓存策略)
- 国际化资源文件(配合ResourceBundle使用)
基础操作:如何创建与加载配置文件
第一步:创建Properties对象
Properties props = new Properties();
// 或指定默认值
Properties propsWithDefault = new Properties(new Properties() {{
setProperty("port", "8080");
setProperty("env", "production");
}});
第二步:加载配置文件
从文件系统加载
try (FileInputStream fis = new FileInputStream("config.properties")) {
props.load(fis);
} catch (IOException e) {
e.printStackTrace();
}
从类路径加载(推荐方式)
try (InputStream is = MyClass.class.getClassLoader().getResourceAsStream("config.properties")) {
props.load(is);
} catch (IOException e) {
e.printStackTrace();
}
注意事项:load() 方法默认使用ISO 8859-1编码读取文件,如果配置文件包含中文,请参考后文“中文乱码处理”章节。
第三步:遍历配置文件
props.forEach((key, value) -> System.out.println(key + " = " + value));
// 或使用枚举
Enumeration<?> names = props.propertyNames();
while (names.hasMoreElements()) {
String key = (String) names.nextElement();
System.out.println(key + " = " + props.getProperty(key));
}
读写实战:Properties的CRUD操作详解
读取配置项
// 读取字符串值
String host = props.getProperty("db.host", "localhost");
// 读取数值(需要手动转换)
int port = Integer.parseInt(props.getProperty("db.port", "3306"));
// 读取布尔值
boolean debug = Boolean.parseBoolean(props.getProperty("debug", "false"));
写入与修改配置
props.setProperty("new.key", "newValue");
props.setProperty("db.port", "3307"); // 修改已有值
持久化到文件
try (FileOutputStream fos = new FileOutputStream("config.properties")) {
// 包含注释信息
props.store(fos, "数据库配置 - 最后修改于2025年");
} catch (IOException e) {
e.printStackTrace();
}
重要:store() 方法同样使用ISO 8859-1编码输出,当值包含非拉丁字符时,会被自动转义为Unicode码点(例如中文变成\\u4e2d\\u6587)。
完整示例:配置管理器
public class ConfigManager {
private Properties props;
private String filePath;
public ConfigManager(String filePath) {
this.filePath = filePath;
props = new Properties();
load();
}
public void load() {
try (InputStream input = new FileInputStream(filePath)) {
props.load(new InputStreamReader(input, "UTF-8"));
} catch (IOException e) {
// 文件不存在时使用默认值
System.err.println("加载配置失败,使用默认值");
}
}
public String get(String key, String defaultValue) {
return props.getProperty(key, defaultValue);
}
public void set(String key, String value) {
props.setProperty(key, value);
}
public void save() {
try (OutputStream output = new FileOutputStream(filePath)) {
props.store(new OutputStreamWriter(output, "UTF-8"), null);
} catch (IOException e) {
e.printStackTrace();
}
}
}
高级技巧:中文乱码处理与默认值机制
中文乱码的终极解决方案
根本原因:load()和store()默认使用ISO 8859-1编码,不支持中文。
解决方式:使用Reader/Writer指定UTF-8编码读取写入。
// 读取时使用UTF-8
try (InputStream input = new FileInputStream("config.properties");
InputStreamReader reader = new InputStreamReader(input, "UTF-8")) {
props.load(reader);
}
// 写入时使用UTF-8
try (OutputStream output = new FileOutputStream("config.properties");
OutputStreamWriter writer = new OutputStreamWriter(output, "UTF-8")) {
props.store(writer, "配置说明(支持中文)");
}
注意:如果已有配置文件使用了ISO 8859-1且包含转义后的中文(\\u4e2d\\u6587),需先手动解码或编写转换工具。
默认值机制:三级回退策略
// 第一级:直接提供的默认值
String value = props.getProperty("key", "default1");
// 第二级:构造时传入的默认Properties
Properties globalDefaults = new Properties();
globalDefaults.setProperty("key", "default2");
Properties appProps = new Properties(globalDefaults);
String value = appProps.getProperty("key"); // 返回"default2"
// 第三级:硬编码常量
public static final String DEFAULT_PORT = "8080";
String port = props.getProperty("port", DEFAULT_PORT);
配置文件的规范化格式
# 注释以井号开头 db.url=jdbc:mysql://localhost:3306/mydb db.username=root # 多行值用反斜杠连接 db.description=A database for \ e-commerce system # 保留转义字符:\t表示制表符 config.special=hello\tworld
常见问答:面试官最常问的3个问题
Q1:Properties和HashMap有什么区别?
A:Properties继承自Hashtable,因此是线程安全的;而HashMap非线程安全,Properties专为配置文件设计,提供load()和store()方法直接与文件交互,且支持默认值查找,但注意Properties的Key和Value必须为String类型,而HashMap支持泛型。
Q2:如何从XML文件加载配置?
A:Properties提供了loadFromXML(InputStream in)方法,可以直接解析XML格式的配置文件。
try (InputStream is = new FileInputStream("config.xml")) {
props.loadFromXML(is);
}
相应的XML格式:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="db.host">localhost</entry>
<entry key="db.port">3306</entry>
</properties>
Q3:为什么我的配置文件修改后没有生效?
A:常见原因有3个:
- 文件路径错误,程序读取的是打包后的classpath路径而非实际部署路径。
- 使用了
getResourceAsStream()但文件未在构建时复制到输出目录。 - 缓存问题:某些框架会将配置缓存到内存中,解决方案:使用绝对路径读取,或框架提供热加载机制(如Spring的
@RefreshScope)。
最佳实践:企业级配置文件管理策略
分层配置设计
config/
├── application.properties # 基础配置
├── application-dev.properties # 开发环境
├── application-prod.properties # 生产环境
└── application-local.properties # 本地覆盖(不提交至版本控制)
敏感信息加密
// 使用自定义解密器
public class EncryptedProperties extends Properties {
@Override
public synchronized String getProperty(String key) {
String value = super.getProperty(key);
if (value != null && value.startsWith("ENC(")) {
return decrypt(value.substring(4, value.length()-1));
}
return value;
}
}
统一配置加载工具
推荐使用第三方库简化处理,如Apache Commons Configuration或Spring Boot的@ConfigurationProperties,但若需轻量级方案,可参考以下模式:
// 单例模式配置中心
public enum ConfigCenter {
INSTANCE;
private Properties props = new Properties();
ConfigCenter() {
try (InputStream is = getClass().getResourceAsStream("/app.properties")) {
props.load(new InputStreamReader(is, "UTF-8"));
} catch (IOException e) {
throw new RuntimeException("初始化配置失败", e);
}
}
public String get(String key) { return props.getProperty(key); }
}
版本控制建议
- 将
.properties文件加入.gitignore(若包含密码) - 提供
.properties.template模板文件供开发者参考 - 使用环境变量或K8s ConfigMap替代敏感配置
延伸阅读:如果要处理更复杂的配置格式(如YAML、JSON、TOML),推荐使用Jackson或SnakeYAML,Properties类虽轻量,但已能覆盖80%的配置文件场景,掌握它相当于掌握了Java配置管理的基石。