Java读取.properties文件最稳妥方式是用Properties类配合ClassLoader.getResourceAsStream()并指定UTF-8编码,避免硬编码路径、文件流及默认编码问题;它不支持嵌套和变量引用,多环境需手动切换文件,Properties非线程安全但只读操作安全,热更新应借助配置中心。

Java里读取.properties文件最稳妥的方式是用Properties类配合ClassLoader.getResourceAsStream()
硬编码FileInputStream路径或直接用new FileInputStream("config.properties")在打包成.jar后必然失败——资源不在文件系统里,而在JAR包内。必须走类路径加载。
常见错误现象:FileNotFoundException、空配置、中文乱码(尤其Windows下默认GBK写入但UTF-8读取)。
- 始终用
getClass().getClassLoader().getResourceAsStream("config.properties"),不要拼绝对路径 - 如果文件在
src/main/resources下,传入的路径就是"config.properties";若在子目录如conf/,则写"conf/config.properties" - 显式指定字符集:
properties.load(new InputStreamReader(input, StandardCharsets.UTF_8)),避免JDK版本差异导致默认编码不一致
为什么Properties.load()不支持嵌套和变量引用?
Properties本质是Hashtable的子类,只处理key=value扁平结构,不解析占位符(如${db.url})、不支持层级(如database.host只是普通key,不是嵌套对象)。
这意味着:你不能靠原生Properties实现类似Spring Boot的@Value("${redis.port}")或YAML那种缩进结构。
立即学习“Java免费学习笔记(深入)”;
- 若需要变量替换,得自己扫描
value中的${...}并递归替换(注意循环引用风险) - 若需分组管理,只能按命名约定,比如用
redis.host、redis.port,再用string.startsWith("redis.")筛选 - 别试图重写
load()去支持JSON/YAML语法——那是配置中心或第三方库(如Apache Commons Configuration)的事
多环境配置怎么切?Java原生Properties没内置profile机制
Spring Boot的application-dev.properties是框架层抽象,java.util.Properties本身不识别环境后缀。你得手动控制加载哪个文件。
典型做法是通过JVM参数或系统属性决定加载路径:
String env = System.getProperty("env", "prod");
String fileName = "config-" + env + ".properties";
InputStream is = MyClass.class.getClassLoader().getResourceAsStream(fileName);
- 确保所有环境配置文件都放在
resources目录下,且命名统一(如config-dev.properties、config-test.properties) - 启动时加
-Denv=dev,否则默认加载config-prod.properties - 别依赖
os.name自动切环境——开发机是Mac、测试机是Linux、生产是CentOS,逻辑会失控
性能与线程安全:Properties实例能不能复用?
Properties不是线程安全的,但load()只在初始化时调用一次;之后的getProperty()是只读操作,无并发问题。真正要注意的是“何时加载”和“是否重复加载”。
- 用静态块或
static final Properties保证单例加载,避免每次调用都打开流、解析文本 - 不要在方法里反复
new Properties().load(...)——IO开销大,且可能因编码不一致导致两次读出不同结果 - 如果配置需热更新(如ZooKeeper推送),原生
Properties不适用,得自己加监听+原子替换引用(例如用AtomicReference)
复杂点在于:一旦引入热加载,就必须考虑旧配置正在被业务线程读取,新旧切换的可见性边界。这时候别硬刚,直接上Consul或Nacos客户端更省心。










