从基础到实战全解析Java加载Properties文件的六种方式

 更新时间:2025年12月29日 10:26:33   作者:醉风塘  
本文详细介绍了Java中Properties文件的六种加载方式,每种方式都有其适用场景、实现步骤、优缺点及最佳实践,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧

在Java开发中,Properties文件是最常用的配置文件格式之一,其以key=value的键值对结构存储配置信息(如数据库连接参数、接口地址、系统开关等),具有简洁易维护、解耦配置与代码的核心优势。不同场景下(如普通Java项目、Spring项目、Web应用、Java 9+模块化项目),Properties文件的加载方式存在差异。本文将详细拆解六种主流加载方式,包含适用场景、实现步骤、代码示例、优缺点及最佳实践,帮助开发者灵活应对各类配置加载需求。

一、核心前提:Properties文件基础

1. 文件格式与规范

  • 后缀名:.properties(默认)或.config(自定义)
  • 编码:默认ISO-8859-1(不支持中文),推荐显式指定UTF-8
  • 内容格式:key=value(等号可替换为:),注释以#!开头
  • 示例(config.properties):
# 数据库配置
db.url=jdbc:mysql://localhost:3306/test
db.username=root
db.password=123456
# 系统配置(中文需UTF-8编码)
system.name=测试系统

2. 核心API

Java通过java.util.Properties类操作Properties文件,核心方法:

  • load(InputStream inStream):从字节流加载配置(默认ISO-8859-1编码)
  • load(Reader reader):从字符流加载配置(支持指定编码,如UTF-8)
  • getProperty(String key):获取指定key的value(无值时返回null)
  • getProperty(String key, String defaultValue):获取value,无值时返回默认值

二、六种加载方式详解

方式一:ClassLoader.getResourceAsStream()(类路径加载,最常用)

适用场景

  • 普通Java项目、Spring Boot项目
  • 配置文件放在classpath下(如src/main/resources目录)
  • 需跨环境(开发/测试/生产)移植,无需关心文件系统绝对路径

核心原理

通过类加载器(ClassLoader)读取classpath下的资源文件,路径以classpath根目录为基准,无需写绝对路径,支持打包后(JAR/WAR)的资源加载。

实现步骤与代码示例

  1. 配置文件位置:src/main/resources/config.properties(Maven/Gradle项目标准目录)
  2. 加载代码(支持三种ClassLoader获取方式):
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class PropertiesLoader1 {
    public static void main(String[] args) {
        Properties props = new Properties();
        // 方式1:当前类的ClassLoader(推荐,避免线程上下文类加载器问题)
        try (InputStreamReader isr = new InputStreamReader(
                PropertiesLoader1.class.getClassLoader().getResourceAsStream("config.properties"),
                StandardCharsets.UTF_8)) { // 显式指定UTF-8编码,解决中文乱码
            props.load(isr);
        } catch (IOException e) {
            throw new RuntimeException("加载配置文件失败", e);
        }
        // 方式2:Thread上下文类加载器(适用于多线程/框架场景)
        /*try (InputStreamReader isr = new InputStreamReader(
                Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"),
                StandardCharsets.UTF_8)) {
            props.load(isr);
        } catch (IOException e) {
            throw new RuntimeException("加载配置文件失败", e);
        }*/
        // 方式3:系统类加载器(与方式1效果一致,不推荐)
        /*try (InputStreamReader isr = new InputStreamReader(
                ClassLoader.getSystemClassLoader().getResourceAsStream("config.properties"),
                StandardCharsets.UTF_8)) {
            props.load(isr);
        } catch (IOException e) {
            throw new RuntimeException("加载配置文件失败", e);
        }*/
        // 读取配置
        System.out.println("数据库URL:" + props.getProperty("db.url"));
        System.out.println("系统名称:" + props.getProperty("system.name")); // 中文正常显示
    }
}

路径规则

  • 相对路径:直接写文件名(如"config.properties"),默认从classpath根目录查找
  • 子目录:若文件在src/main/resources/config/db.properties,路径为"config/db.properties"
  • 禁止写绝对路径(如"D:/config.properties"),类加载器仅识别classpath下的资源

优缺点

  • 优点:跨环境移植性强、支持JAR包内资源、无需关心文件系统路径
  • 缺点:仅能加载classpath下的文件,无法加载外部文件系统的配置

方式二:FileInputStream(文件系统路径加载)

适用场景

  • 配置文件放在项目外部(如服务器特定目录、用户目录)
  • 需动态指定配置文件路径(如通过命令行参数传入)
  • classpath下的本地文件加载

核心原理

通过文件系统的绝对路径或相对路径,直接读取文件字节流,依赖操作系统的文件系统接口。

实现步骤与代码示例

  1. 配置文件位置:D:/config/config.properties(绝对路径)或./config.properties(项目根目录相对路径)
  2. 加载代码:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class PropertiesLoader2 {
    public static void main(String[] args) {
        Properties props = new Properties();
        String filePath;
        // 方式1:绝对路径(Windows/Dinux通用,Linux路径如"/opt/config/config.properties")
        filePath = "D:/config/config.properties";
        // 方式2:相对路径(基准目录为项目根目录,如IDEA中为项目文件夹)
        // filePath = "./config.properties";
        // 方式3:命令行参数传入路径(灵活适配不同环境)
        // if (args.length > 0) filePath = args[0];
        try (InputStreamReader isr = new InputStreamReader(
                new FileInputStream(filePath),
                StandardCharsets.UTF_8)) { // 指定UTF-8编码
            props.load(isr);
        } catch (IOException e) {
            throw new RuntimeException("加载配置文件失败,路径:" + filePath, e);
        }
        // 读取配置
        System.out.println("数据库用户名:" + props.getProperty("db.username"));
        System.out.println("数据库密码:" + props.getProperty("db.password"));
    }
}

路径规则

  • 绝对路径:包含完整的盘符(Windows)或根目录(Linux),如"D:/config.properties""/opt/config.properties"
  • 相对路径:以当前工作目录为基准(IDEA中为项目根目录,JAR运行时为启动命令所在目录),如"./conf/config.properties"(项目根目录下的conf文件夹)
  • 注意:相对路径的基准目录可能因运行环境变化(如IDE、脚本启动、容器部署),需谨慎使用

优缺点

  • 优点:可加载任意位置的文件、路径灵活配置
  • 缺点:移植性差(路径依赖操作系统)、需手动处理路径正确性、打包后无法加载JAR内的资源

方式三:Spring框架加载(@PropertySource + @Value)

适用场景

  • Spring Framework、Spring Boot项目
  • 需集成Spring的依赖注入(DI),自动注入配置属性
  • 支持多配置文件加载、占位符解析、配置优先级管理

核心原理

Spring通过@PropertySource注解指定配置文件路径,由PropertySourcesPlaceholderConfigurer自动加载配置,结合@Value注解注入属性,支持classpath、文件系统路径、URL等多种资源。

实现步骤与代码示例

1. 普通Spring项目(XML配置)

<!-- applicationContext.xml -->
<context:component-scan base-package="com.example"/>
<context:property-placeholder 
    location="classpath:config.properties,file:D:/config/ext-config.properties" 
    file-encoding="UTF-8"/> <!-- 支持多文件、混合路径、指定编码 -->
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class SpringConfigLoader {
    // 注入配置属性,支持默认值
    @Value("${db.url}")
    private String dbUrl;
    @Value("${db.username}")
    private String dbUsername;
    @Value("${system.name:默认系统}") // 无该key时返回默认值
    private String systemName;
    // 测试方法
    public void printConfig() {
        System.out.println("Spring加载 - 数据库URL:" + dbUrl);
        System.out.println("Spring加载 - 系统名称:" + systemName);
    }
}

2. Spring Boot项目(注解驱动)

Spring Boot默认加载classpath:application.properties/application.yml,若需加载自定义文件,使用@PropertySource

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
// 加载classpath下的config.properties和外部文件
@Configuration
@PropertySource(value = {
        "classpath:config.properties",
        "file:D:/config/ext-config.properties"
}, encoding = "UTF-8") // 指定UTF-8编码(Spring 4.3+支持)
public class BootConfigLoader {
    @Value("${db.url}")
    private String dbUrl;
    @Value("${db.password}")
    private String dbPassword;
    @Value("${system.version:1.0.0}")
    private String systemVersion;
    // 提供getter方法供业务使用
    public String getDbUrl() {
        return dbUrl;
    }
    public String getDbPassword() {
        return dbPassword;
    }
}

3. Spring Boot 2.4+ 推荐方式(application.properties指定额外配置)

# application.properties
spring.config.import=classpath:config.properties,file:D:/config/ext-config.properties

路径规则

  • classpath:前缀:加载classpath下的文件(如classpath:config.properties
  • file:前缀:加载文件系统路径(如file:D:/config.properties
  • 无前缀:默认按classpath查找
  • 支持URL路径:如https://config.example.com/config.properties(需网络可达)

优缺点

  • 优点:集成Spring生态、支持依赖注入、自动解析占位符、多文件加载、配置优先级管理
  • 缺点:依赖Spring框架、非Spring项目无法使用

方式四:Java 9+ Module资源加载(Module.getResourceAsStream())

适用场景

  • Java 9及以上模块化项目(使用module-info.java
  • 需遵循模块的资源访问控制(避免非模块访问模块内资源)
  • 模块化打包(JMOD/JAR)后的资源加载

核心原理

Java 9引入模块系统(Module System)后,传统ClassLoader加载资源可能受模块权限限制,需通过Module接口的getResourceAsStream()方法加载模块内的资源,支持模块间的资源访问控制。

实现步骤与代码示例

  1. 模块化项目结构:
src/
├── main/
│   ├── java/
│   │   ├── com/
│   │   │   └── example/
│   │   │       └── ModuleConfigLoader.java
│   │   └── module-info.java
│   └── resources/
│       └── config.properties
  1. module-info.java配置(关键:开放资源访问权限):
// 模块名:com.example.config
module com.example.config {
    // 允许其他模块访问本模块的资源(可选,若仅内部使用可省略)
    opens com.example to java.base;
    // 导出包(若需外部模块使用加载类)
    exports com.example;
}
  1. 加载代码:
package com.example;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class ModuleConfigLoader {
    public static void main(String[] args) {
        Properties props = new Properties();
        // 方式1:通过当前类的Module加载(推荐)
        try (InputStreamReader isr = new InputStreamReader(
                ModuleConfigLoader.class.getModule().getResourceAsStream("config.properties"),
                StandardCharsets.UTF_8)) {
            props.load(isr);
        } catch (IOException e) {
            throw new RuntimeException("模块内加载配置文件失败", e);
        }
        // 方式2:通过模块名获取Module(需模块已加载)
        /*Module module = ModuleLayer.boot().findModule("com.example.config").orElseThrow();
        try (InputStreamReader isr = new InputStreamReader(
                module.getResourceAsStream("config.properties"),
                StandardCharsets.UTF_8)) {
            props.load(isr);
        } catch (IOException e) {
            throw new RuntimeException("加载模块资源失败", e);
        }*/
        // 读取配置
        System.out.println("模块加载 - 数据库URL:" + props.getProperty("db.url"));
        System.out.println("模块加载 - 系统名称:" + props.getProperty("system.name"));
    }
}

关键注意事项

  • 模块内资源默认仅允许模块内部访问,若需外部模块访问,需在module-info.java中通过opens语句开放资源所在包
  • 资源路径以模块的classpath为基准,与传统类加载器路径规则一致
  • 避免使用ClassLoader加载模块化项目的资源,可能因模块权限限制失败

优缺点

  • 优点:符合Java模块化规范、资源访问可控、支持模块化打包
  • 缺点:仅支持Java 9+、需额外配置module-info.java、非模块化项目无法使用

方式五:Apache Commons Configuration(第三方库加载)

适用场景

  • 需简化加载逻辑(无需手动处理流、编码)
  • 支持多种配置格式(Properties、XML、JSON等)
  • 需高级特性(配置刷新、变量插值、多文件合并)

核心原理

Apache Commons Configuration是Apache开源项目,提供了更强大的配置加载API,封装了流处理、编码转换、异常处理等细节,支持classpath、文件系统、URL等多种资源。

实现步骤与代码示例

  1. 引入依赖(Maven):
<!-- Apache Commons Configuration 2.x -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-configuration2</artifactId>
    <version>2.10.1</version>
</dependency>
<!-- 依赖 Commons Lang 和 Commons Collections -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version>
</dependency>
  1. 加载代码:
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.ex.ConfigurationException;
public class CommonsConfigLoader {
    public static void main(String[] args) {
        PropertiesConfiguration config;
        try {
            // 方式1:加载classpath下的文件
            config = new PropertiesConfiguration("config.properties");
            // 方式2:加载文件系统路径
            // config = new PropertiesConfiguration("D:/config/config.properties");
            // 方式3:指定编码(默认UTF-8,无需额外处理中文)
            // config = new PropertiesConfiguration();
            // config.setEncoding("UTF-8");
            // config.load("classpath:config.properties");
        } catch (ConfigurationException e) {
            throw new RuntimeException("加载配置文件失败", e);
        }
        // 读取配置(支持默认值、类型转换)
        String dbUrl = config.getString("db.url");
        String dbUsername = config.getString("db.username");
        String systemName = config.getString("system.name", "默认系统"); // 默认值
        int dbPort = config.getInt("db.port", 3306); // 类型转换+默认值
        System.out.println("Commons加载 - 数据库URL:" + dbUrl);
        System.out.println("Commons加载 - 数据库端口:" + dbPort);
        System.out.println("Commons加载 - 系统名称:" + systemName);
    }
}

核心特性

  • 自动处理编码(默认UTF-8),无需手动创建InputStreamReader
  • 支持类型转换(getIntgetBoolean等)
  • 支持配置刷新(config.refresh()
  • 支持多文件合并(CompositeConfiguration
  • 支持变量插值(如key=${other.key}

优缺点

  • 优点:API简洁、功能强大、支持多种格式、无需手动处理流
  • 缺点:需引入第三方依赖、增加项目体积

方式六:ServletContext.getResourceAsStream()(Web应用专属)

适用场景

  • Java Web应用(Servlet、JSP、SSM等)
  • 配置文件放在WEB-INF目录下(安全,不允许客户端直接访问)
  • 需通过Servlet上下文加载Web应用内的资源

核心原理

Web应用启动时,Servlet容器(Tomcat、Jetty)会创建ServletContext(Servlet上下文),通过其getResourceAsStream()方法可加载Web应用目录下的资源,路径以/开头,基准目录为Web应用根目录(WEB-INF的上级目录)。

实现步骤与代码示例

  1. 配置文件位置:WEB-INF/config/config.properties(Web应用目录)
  2. 加载代码(Servlet中):
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
@WebServlet("/configLoader")
public class ServletConfigLoader extends HttpServlet {
    private Properties props;
    // 初始化时加载配置(Servlet生命周期)
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        props = new Properties();
        // 通过ServletContext获取资源流,路径以"/"开头(基准为Web应用根目录)
        String resourcePath = "/WEB-INF/config/config.properties";
        try (InputStreamReader isr = new InputStreamReader(
                getServletContext().getResourceAsStream(resourcePath),
                StandardCharsets.UTF_8)) {
            props.load(isr);
        } catch (IOException e) {
            throw new ServletException("Web应用加载配置文件失败,路径:" + resourcePath, e);
        }
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/plain;charset=UTF-8");
        // 读取配置并响应
        String dbUrl = props.getProperty("db.url");
        String systemName = props.getProperty("system.name");
        resp.getWriter().write("Web加载 - 数据库URL:" + dbUrl + "\n");
        resp.getWriter().write("Web加载 - 系统名称:" + systemName);
    }
}

路径规则

  • 路径以/开头:基准目录为Web应用根目录(如Tomcat的webapps/应用名/
  • 示例路径:
    • /WEB-INF/config.propertiesWEB-INF目录下的配置文件
    • /resources/config.properties:Web应用根目录下的resources文件夹
  • 禁止写绝对路径,仅支持Web应用内的相对路径

优缺点

  • 优点:安全(WEB-INF目录不暴露给客户端)、适配Web应用目录结构
  • 缺点:仅支持Web应用、依赖Servlet容器、非Web项目无法使用

三、六种加载方式对比总结

加载方式适用场景核心优点核心缺点
ClassLoader.getResourceAsStream()普通Java项目、Spring Boot项目跨环境移植性强、支持JAR内资源、无需路径依赖仅加载classpath下文件
FileInputStream外部配置文件、动态指定路径可加载任意位置文件、路径灵活移植性差、需手动处理路径正确性
Spring框架(@PropertySource)Spring生态项目支持DI注入、占位符解析、多文件加载依赖Spring框架
Java 9+ Module加载模块化项目(Java 9+)资源访问可控、符合模块化规范仅支持Java 9+、需配置module-info.java
Apache Commons Configuration需高级配置特性(多格式、刷新)API简洁、功能强大、自动处理编码需引入第三方依赖
ServletContext.getResourceAsStream()Web应用安全(WEB-INF)、适配Web目录结构仅支持Web应用、依赖Servlet容器

四、最佳实践

1. 配置文件存放位置

  • 普通Java项目:src/main/resources(classpath根目录),子目录按功能划分(如resources/config/db.properties
  • Web应用:WEB-INF/config(避免客户端直接访问)
  • 外部配置:生产环境建议放在服务器独立目录(如/opt/config),通过环境变量或命令行参数指定路径

2. 编码处理规范

  • 强制指定UTF-8编码:使用InputStreamReader(原生API)或框架自带的编码配置(Spring、Commons Configuration),避免中文乱码
  • 禁止在Properties文件中直接写中文(即使指定UTF-8,部分工具可能不兼容),推荐使用Unicode编码(如system.name=\u6d4b\u8bd5\u7cfb\u7edf

3. 路径写法规范

  • 优先使用classpath:前缀(Spring项目)或相对classpath路径(ClassLoader方式),避免绝对路径
  • 多环境适配:通过环境变量(如${CONFIG_PATH})或配置中心(Nacos、Apollo)管理路径,避免硬编码

4. 避免硬编码

  • 禁止在代码中写死配置文件路径(如"D:/config.properties"),通过命令行参数、环境变量、Spring Profiles等方式动态指定
  • 示例(Spring Boot多环境):
# application-dev.properties(开发环境)
config.path=classpath:config-dev.properties
# application-prod.properties(生产环境)
config.path=file:/opt/config/config-prod.properties

5. 配置刷新机制

  • 静态配置:加载一次即可(如数据库连接参数)
  • 动态配置:需支持刷新(如通过Apache Commons Configuration的refresh()方法,或配置中心推送更新)

五、常见问题排查

问题现象根因分析解决方案
中文乱码未指定UTF-8编码,默认ISO-8859-1不支持中文使用InputStreamReader指定UTF-8,或框架编码配置
找不到配置文件(FileNotFoundException)路径错误(绝对路径不存在、相对路径基准错误)检查路径正确性、使用绝对路径测试、打印System.getProperty("user.dir")确认基准目录
ClassLoader加载不到文件文件未放在classpath下、路径写绝对路径移至src/main/resources、使用相对classpath路径
Spring @Value注入为null未加@PropertySource、配置文件路径错误、未扫描组件检查注解配置、路径正确性、@Component扫描范围
模块化项目加载失败模块未开放资源访问权限module-info.java中添加opens 包名 to 模块名

六、总结

Java加载Properties文件的六种方式各有适配场景,核心选择原则:

  • 普通Java项目/ Spring Boot项目:优先使用ClassLoader.getResourceAsStream()或Spring的@PropertySource
  • 外部配置文件/动态路径:使用FileInputStream或命令行参数+classpath混合方式
  • Web应用:使用ServletContext.getResourceAsStream()
  • Java 9+模块化项目:使用Module.getResourceAsStream()
  • 需高级特性:使用Apache Commons Configuration

实际开发中,需结合项目类型(普通Java、Spring、Web、模块化)、配置存放位置(classpath内/外)、功能需求(动态刷新、多环境)选择合适的加载方式,并遵循编码规范、路径规范、避免硬编码等最佳实践,确保配置加载的可靠性和可维护性。

到此这篇关于Java加载Properties文件的六种方式:从基础到实战全解析的文章就介绍到这了,更多相关Java加载Properties文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文了解Java 线程池的正确使用姿势

    一文了解Java 线程池的正确使用姿势

    线程池在平时的工作中出场率非常高,基本大家多多少少都要了解过,可能不是很全面,本文和大家基于jdk8学习下线程池的全面使用,以及分享下使用过程中遇到的一些坑,希望对大家有所帮助
    2022-10-10
  • 聊聊Java的switch为什么不支持long

    聊聊Java的switch为什么不支持long

    这篇文章主要介绍了Java的switch为什么不支持long,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • feign调用中文参数被encode编译的问题

    feign调用中文参数被encode编译的问题

    这篇文章主要介绍了feign调用中文参数被encode编译的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Spring Boot Admin微服务应用监控的实现

    Spring Boot Admin微服务应用监控的实现

    这篇文章主要介绍了Spring Boot Admin微服务应用监控,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • 带你入门Java的集合

    带你入门Java的集合

    Java的集合类型都是对java.util包中Collection接口的继承,这里我们主要介绍依赖于collection的一些主分支,一起来看一下Java中的collection集合类型总结
    2021-07-07
  • 深入Java冒泡排序与选择排序的区别详解

    深入Java冒泡排序与选择排序的区别详解

    本篇文章是对Java冒泡排序与选择排序的区别进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 深入剖析Java编程中的序列化

    深入剖析Java编程中的序列化

    这篇文章主要介绍了深入剖析Java编程中的序列化,文中谈到了序列化时对象的继承等各种问题,案例详尽,强烈推荐!需要的朋友可以参考下
    2015-07-07
  • Java--装箱和拆箱详解

    Java--装箱和拆箱详解

    本篇文章主要介绍了详解Java 自动装箱与拆箱的实现原理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-07-07
  • springboot自定义日志注解的实现

    springboot自定义日志注解的实现

    本文主要介绍了springboot自定义日志注解的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Java annotation元注解原理实例解析

    Java annotation元注解原理实例解析

    这篇文章主要介绍了Java annotation元注解原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03

最新评论