Java常用配置文件处理类库与Properties

最稳妥方式取决于项目类型:纯Java项目必须用Properties类;Spring Boot项目优先用@Value或@ConfigurationProperties,因其支持占位符解析、类型转换和配置刷新,而Properties仅返回String且需手动处理编码、路径及线程安全等问题。

Java里读取application.properties最稳妥的方式是用Properties类还是Spring Boot的@Value

纯Java项目(无Spring)必须用Properties;Spring Boot项目优先用@Value@ConfigurationProperties,不是因为“更高级”,而是Properties类不处理占位符、类型转换、配置刷新等实际需求。Properties读出来全是String,连int都要手动Integer.parseInt(),出错就NumberFormatException

常见错误现象:

  • Properties.load(new FileInputStream("app.properties"))但没指定字符集,中文乱码
  • 路径写成"./config/app.properties",结果在JAR包里找不到——FileInputStream只认文件系统路径,不认classpath资源
  • 多个properties文件手动load(),覆盖逻辑混乱,没有合并策略

Properties加载时字符编码出错怎么 fix

Properties默认用ISO-8859-1解析,哪怕文件存为UTF-8,中文也会变问号或乱码。不能靠改编辑器编码糊弄,得在代码里显式指定。

正确做法:

  • InputStreamReader包装流,传入StandardCharsets.UTF_8
  • 调用Properties.load(Reader)而非load(InputStream)
  • 避免用Properties.loadFromXML()——它也只认UTF-8,且格式更重,不兼容普通.properties
Properties props = new Properties();
try (InputStream is = getClass().getResourceAsStream("/application.properties");
     Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
    props.load(reader);
}

为什么别直接用System.setProperty()覆盖Properties里的值

System.setProperty()改的是JVM全局系统属性,和你的Properties对象完全无关。它不会影响已加载的props.getProperty("xxx")结果,也不会触发任何监听或重载逻辑。

真正需要“动态改配置”时:

  • 如果是Spring环境,用ConfigurableEnvironmentgetPropertySources().addFirst(...)
  • 如果自己维护Properties实例,就直接props.setProperty("key", "value"),但要注意线程安全——Properties不是线程安全的
  • 想让后续所有props.getProperty()返回新值?必须确保你操作的是同一个实例,且没被其他地方缓存副本

第三方库如Apache Commons Configuration 2比原生Properties强在哪

它解决的不是“能不能读”,而是“读得稳不稳、扩不扩展、换不换源”。比如:

  • 自动识别application.ymlapplication.jsonapplication.properties并统一API访问
  • 支持${database.url}嵌套占位符,自动递归解析
  • 可监听文件变化,触发ConfigurationListener回调
  • 能叠加多个配置源(系统属性 + 环境变量 + 文件),按优先级覆盖

但代价是引入约3MB依赖,且API较重。小项目、脚本工具类,原生Properties加几行封装更轻量。

复杂点在于:一旦用了多源叠加,就必须理清各配置源的优先级顺序,否则dev环境跑出prod配置,排查起来不看源码根本没法定位。