杰瑞科技汇

Java properties文件如何正确加载?

什么是 Properties 文件?

我们来看一个典型的 config.properties 文件示例:

Java properties文件如何正确加载?-图1
(图片来源网络,侵删)
# Database Configuration
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/mydb
db.username=root
db.password=secret
# Application Settings
app.name=My Awesome App
app.version=1.0.0

文件中的 开头的是注释,键和值用 或 分隔。


核心加载方法

Java 提供了多种加载 Properties 文件的方式,适用于不同的场景(从类路径加载、从文件系统加载、从网络加载等)。

使用 ClassLoader.getResourceAsStream() (推荐用于类路径资源)

这是最常见、最推荐的方法,尤其适用于在 Maven 或 Gradle 项目中,将配置文件放在 src/main/resources 目录下的情况。

工作原理: 这种方式将 Properties 文件视为类路径(Classpath)中的一个资源,由类加载器负责加载,这使得应用程序打包成 JAR 文件后,配置文件依然可以正常读取。

Java properties文件如何正确加载?-图2
(图片来源网络,侵删)

代码示例:

import java.io.InputStream;
import java.util.Properties;
public class PropertiesLoaderWithClassLoader {
    public static void main(String[] args) {
        // 1. 创建 Properties 对象
        Properties props = new Properties();
        // 2. 使用 try-with-resources 确保 InputStream 自动关闭
        try (InputStream input = PropertiesLoaderWithClassLoader.class.getClassLoader().getResourceAsStream("config.properties")) {
            // 3. 检查输入流是否为空
            if (input == null) {
                System.out.println("Sorry, unable to find config.properties");
                return;
            }
            // 4. 加载 Properties 文件
            props.load(input);
            // 5. 读取并打印属性
            System.out.println("Database URL: " + props.getProperty("db.url"));
            System.out.println("Username: " + props.getProperty("db.username"));
            System.out.println("App Name: " + props.getProperty("app.name"));
            System.out.println("App Version: " + props.getProperty("app.version"));
            // 如果属性不存在,可以提供默认值
            System.out.println("Debug Mode: " + props.getProperty("debug.mode", "false"));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

关键点:

  • getClassLoader().getResourceAsStream("config.properties")config.properties 的路径是相对于类路径的根目录的。
  • 文件位置: 如果你的项目是 Maven 项目,需要将 config.properties 放在 src/main/resources 目录下。
  • 路径问题: 路径中不要以 开头,否则会从类路径的根开始查找,如果要以 开头,应该使用 Class.getResourceAsStream()

使用 Class.getResourceAsStream()

与方法一类似,但路径的解析方式略有不同。

工作原理: 如果路径以 开头,则从类路径的根目录查找,如果路径不以 开头,则从当前类的包路径下查找。

代码示例:

假设你的类是 com.example.PropertiesLoaderconfig.propertiessrc/main/resources/com/example/ 目录下。

import java.io.InputStream;
import java.util.Properties;
public class PropertiesLoaderWithClass {
    public static void main(String[] args) {
        Properties props = new Properties();
        // 假设 config.properties 和这个类在同一个包下
        // 路径不以 '/' 开头,从当前类的包下查找
        try (InputStream input = PropertiesLoaderWithClass.class.getResourceAsStream("config.properties")) {
            if (input == null) {
                System.out.println("Sorry, unable to find config.properties in the same package.");
                return;
            }
            props.load(input);
            System.out.println("App Name: " + props.getProperty("app.name"));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

关键点:

  • 路径前缀: 路径前是否有 决定了查找的起点。
  • 灵活性: 当配置文件和类在同一个包下时,这种方式很方便。

使用 FileInputStream (用于从文件系统加载)

如果你的配置文件在项目之外的某个固定位置,或者你想通过绝对路径/相对路径来加载,这种方法非常直接。

代码示例:

假设 config.properties 文件位于项目根目录下的 config 文件夹中。

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesLoaderWithFileInputStream {
    public static void main(String[] args) {
        Properties props = new Properties();
        // 使用绝对路径
        // String filePath = "C:/path/to/your/config/config.properties";
        // 使用相对路径 (相对于项目根目录)
        String filePath = "config/config.properties";
        try (FileInputStream input = new FileInputStream(filePath)) {
            props.load(input);
            System.out.println("Database URL: " + props.getProperty("db.url"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

关键点:

  • 路径灵活性: 可以是绝对路径或相对于当前工作目录(通常是项目根目录)的相对路径。
  • 依赖文件系统: 应用程序部署后,必须确保该文件存在于指定路径,否则会抛出 FileNotFoundException,这使得应用程序的可移植性变差。

使用 java.util.ResourceBundle (国际化专用)

ResourceBundle 主要用于国际化(i18n),但它也可以用来加载 Properties 文件,它不返回 Properties 对象,而是允许你按需获取键对应的值。

工作原理: ResourceBundle 会根据默认的 Locale(或指定的 Locale)查找匹配的文件,文件命名规则是 basename_<locale>.propertiesmessages_en_US.properties,如果没有特定地区的文件,则加载 messages.properties

代码示例:

假设 config.properties 文件在 src/main/resources 目录下。

import java.util.ResourceBundle;
public class PropertiesLoaderWithResourceBundle {
    public static void main(String[] args) {
        // 1. 基础名称,不包含 .properties 后缀
        // ResourceBundle 会自动从类路径中查找
        String baseName = "config";
        // 2. 获取 ResourceBundle 对象
        // 会自动加载 config.properties 或 config_<locale>.properties
        ResourceBundle rb = ResourceBundle.getBundle(baseName);
        // 3. 获取值
        // 如果键不存在,会抛出 MissingResourceException
        System.out.println("App Name: " + rb.getString("app.name"));
        System.out.println("Username: " + rb.getString("db.username"));
        // 获取带默认值的值(需要自己实现,ResourceBundle本身不直接支持)
        String debugMode = rb.containsKey("debug.mode") ? rb.getString("debug.mode") : "false";
        System.out.println("Debug Mode: " + debugMode);
    }
}

关键点:

  • 国际化: 这是它的主要设计用途。
  • 性能: ResourceBundle 会被缓存,多次调用 getBundle 获取相同的 baseName 会返回同一个实例,性能较好。
  • 限制: 主要用于读取,不能像 Properties 对象那样进行修改或重新加载。

总结与最佳实践

方法 适用场景 优点 缺点
ClassLoader.getResourceAsStream() 推荐,配置文件在类路径中(如 src/main/resources)。 与项目结构解耦,可移植性好(JAR 内资源),是标准做法。 路径是相对于类路径的,对新手可能有点抽象。
Class.getResourceAsStream() 配置文件与类在同一个包下。 路径解析直观(基于类所在包)。 灵活性不如 ClassLoader 的方法。
FileInputStream 配置文件在项目外的固定位置。 路径非常灵活,绝对/相对路径均可。 可移植性差,依赖文件系统,部署时易出错。
ResourceBundle 国际化/多语言场景。 性能好(缓存),专为 i18n 设计。 不适合动态修改配置,主要用于读取。

最佳实践建议:

  1. 首选 ClassLoader.getResourceAsStream():对于绝大多数 Java 项目,尤其是使用构建工具(Maven/Gradle)的项目,这是最标准、最可靠的方式,将配置文件放在 src/main/resources 目录下。
  2. 处理异常和默认值:始终使用 try-with-resources 来确保流被正确关闭,使用 props.getProperty("key", "default_value") 来避免因键不存在而导致的 NullPointerException
  3. 路径管理:避免在代码中硬编码文件路径,对于 FileInputStream,可以通过环境变量、系统属性或配置文件来指定配置文件的路径,以提高灵活性。
  4. 考虑更高级的配置库:对于复杂的应用,java.util.Properties 可能功能有限,可以考虑使用更强大的库,如:
    • Apache Commons Configuration:支持多种配置源(Properties, XML, JSON, 环境变量等)并能自动合并。
    • Spring Boot @ConfigurationProperties:如果你在使用 Spring Boot,这是最佳实践,它可以将配置文件(application.yml/application.properties)中的属性自动绑定到类型安全的 Java Bean 上。

希望这份详细的指南能帮助你更好地理解和使用 Java 中的 Properties 文件加载!

分享:
扫描分享到社交APP
上一篇
下一篇