




推荐用 getResourceAsStream() 读取 classpath 配置,显式指定 UTF-8 编码并用 try-with-resources 关流;Spring 项目优先用 @ConfigurationProperties;非 Spring 场景需动态刷新时选 Apache Commons Configuration2 或 Nacos。
Java 项目里读配置文件,不推荐手写 Properties 加 FileInputStream——容易漏关流、路径错、编码乱、无法热更新,更别说多环境切换。真正可用的方案得看场景:简单单体用 java.util.Properties 就够;Spring 项目直接走 @Value 或 @ConfigurationProperties;微服务或需动态刷新的,得上 Apache Commons Configuration2 或 Nacos 这类外部配置中心。
Properties 读取 classpath 下的 application.properties
这是最轻量、无依赖的方式,适用于无框架的工具类或小型脚本。关键点不是“能不能读”,而是“怎么读才不出错”:
getResourceAsStream() 必须用,不能用 new FileInputStream("xxx.properties") —— 后者依赖当前工作目录,打包成 jar 后必然 FileNotFoundException
UTF-8 编码,否则 Windows 下中文会变 ???
try-with-resources,否则流不关可能引发句柄泄漏(尤其在频繁 reload 场景)Properties props = new Properties();
try (InputStream is = MyClass.class.getResourceAsStream("/application.properties")) {
if (is == null) {
throw new RuntimeException("application.properties not found in classpath");
}
props.load(is);
} catch (IOException e) {
throw new RuntimeException("Failed to load properties", e);
}
String dbUrl = props.getProperty("db.url");
@ConfigurationProperties 绑定类型安全配置比 @Value 更健壮:支持嵌套对象、校验、松散绑定(my-db-url 自动映射到 myDbUrl),且能统一管理前缀。但容易踩两个坑:
@ConfigurationProperties(prefix = "app"),同时该类要被 Spring 扫描到(加 @Component 或用 @EnableConfigurationProperties)app.redis.password=abc@123),需用单引号包裹,否则 @ 会被 Spring 解析为占位符@RefreshScope + Spring Cloud Config / Nacos)@Component @ConfigurationProperties(prefix = "app.db") public class DatabaseProperties { private String url; private String username; private String password; // getter/setter }
Apache Commons Configuration2 支持多格式+层级+自动重载当项目既不是 Spring Boot,又需要读 XML、YAML、JSON 或监听文件变化时,commons-configuration2 是最成熟的选择。它把不同格式抽象成统一接口,但要注意:
snakeyaml,否则抛 NoClassDefFoundError
FileChangedReloadingStrategy,但它只检测最后修改时间,不感知内容变更(比如改完立刻保存两次,第二次可能被忽略)database.host)默认启用,但若用 PropertiesConfiguration,需手动调用 setListDelimiterHandler(new DefaultListDelimiterHandler(',')) 处理数组FileBasedConfigurationBuilderbuilder = new FileBasedConfigurationBuilder<>(PropertiesConfiguration.class) .configure(new Parameters().properties() .setFileName("config.properties") .setReloadingStrategy(new FileChangedReloadingStrategy())); PropertiesConfiguration config = builder.getConfiguration(); String host = config.getString("database.host");
很多团队在工具类里反复写 new Properties().load(...),结果是:同一配置被多次解析、内存占用上升、修改后不生效。根本解法就一条:
ConcurrentHashMap 缓存已解析的 Properties 实例,key 为文件路径(绝对路径 or classpath 资源名)getProperty,也应提前提取并复用变量*** 掩码处理,否则可能泄露到日志系统路径问题永远是最隐蔽的瓶颈:IDE 里跑得好好的,一打包成 jar 就找不到文件;本地用反斜杠路径能过,Linux 服务器直接报空指针。别信“路径应该没问题”,每次部署前用 ClassLoader.getSystemResource() 打印下实际加载的 URL,比猜强十倍。