You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

模块化Java中子目录资源加载失败问题排查

问题描述

现有一个基于JPMS的模块化Java项目,相关代码与目录结构如下:

Main类代码

package resources;

public class Main {
    public static void main(String[] args) {
        System.out.println(ClassLoader.getSystemResource("toplevel.txt"));
        System.out.println(ClassLoader.getSystemResource("/sub/nested.txt"));
    }
}

module-info.java代码

module resources {
    exports resources;
}

编译后目标目录结构

resources/Main.class
sub/nested.txt
toplevel.txt

程序运行输出

file:/C:/Eclipse/workspace-2023-03/resources/bin/toplevel.txt
null

已知目标目录路径为/C:/Eclipse/workspace-2023-03/resources/bin/,但/sub/nested.txt始终无法被找到。使用JDK 17与Eclipse开发,非模块化项目的解决方案对此场景不适用,请问问题出在哪里?


原因及解决方案

在模块化项目(JPMS)中,资源访问规则与非模块化项目存在本质差异,核心问题出在模块资源的访问权限和路径写法上:

  1. ClassLoader资源查找规则的变化
    JPMS下,ClassLoader.getSystemResource接收的路径如果以/开头,会被自动忽略斜杠,视为相对于模块根的路径,但这不是核心问题——真正的障碍是:模块默认不会开放未声明的资源目录给类加载器访问。

  2. 必须显式开放资源目录的访问权限
    默认情况下,模块化项目中只有模块内的包(通过exports声明)和显式开放的资源目录(通过opens声明)才能被类加载器读取。你需要修改module-info.java,添加对sub目录的开放声明:

    module resources {
        exports resources;
        // 开放sub目录,允许所有模块读取其中的资源
        opens sub to all;
        // 若仅需本模块内部访问,可简化为:opens sub;
    }
    
  3. 修正资源路径写法
    在模块化项目中,ClassLoader.getSystemResource不需要以/开头,直接使用相对模块根的路径即可。修正后的代码:

    System.out.println(ClassLoader.getSystemResource("sub/nested.txt"));
    
  4. 更规范的模块化资源获取方式
    推荐直接通过当前模块获取资源,避免类加载器的路径歧义,代码示例:

    // 获取资源URL
    System.out.println(Main.class.getModule().getResource("sub/nested.txt"));
    // 若需读取资源流,使用:
    // Main.class.getModule().getResourceAsStream("sub/nested.txt");
    

总结:模块化项目中,资源目录必须通过opens声明开放访问权限,同时资源路径无需添加开头的/,遵循模块根相对路径的写法即可解决问题。

内容的提问来源于stack exchange,提问作者Arend

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:25:17