模块化环境下无法访问resources目录的本质是jpms切断类路径隐式访问,必须通过模块显式opens资源包并使用classloader.getresourceasstream()加载,禁用file/paths等文件系统方式。

模块化环境下无法直接访问 resources 目录,本质是 Java 平台模块系统(JPMS)切断了对类路径资源的隐式访问能力。传统 new File("xxx.properties") 或 Paths.get("src/main/resources/...") 在模块化项目中会彻底失效——因为这些路径在运行时根本不存在,JAR 包内资源也不再是文件系统实体。
确认是否处于模块化环境
检查项目根目录是否存在 module-info.java;或查看 JVM 启动参数是否含 --module-path。若存在,说明已启用 JPMS,此时所有资源必须通过模块导出+类加载器加载,不能走文件系统路径。
确保资源所在模块显式导出资源路径
仅声明 requires 不够,资源所在的模块还需将包含资源的包“开放”给其他模块读取。这不是导出代码包,而是开放资源访问权限:
- 在资源模块(如
project-config)的module-info.java中添加:
opens config to project-algo;(假设资源在config/子目录下,且被project-algo模块使用) - 如果资源在模块根路径(即
resources/下无子目录),可写:
opens . to project-algo; -
opens是关键:它允许反射式资源访问,exports只导出类,不导出资源
统一使用 ClassLoader.getResourceAsStream() 加载
无论开发还是打包部署,都应放弃 File、Paths、URL.getFile() 等依赖文件系统的方式。正确做法是:
- 用
Thread.currentThread().getContextClassLoader().getResourceAsStream("config/app.yaml") - 路径以正斜杠开头表示从 classpath 根开始,不加斜杠表示相对于当前类所在包
- 避免使用
getClass().getResource()返回 URL 再调.getFile()—— JAR 内资源 URL 的getFile()会返回形如jar:file:/xxx.jar!/config/app.yaml,无法转为有效File - 如需转为字符串内容,可用
new String(Objects.requireNonNull(is).readAllBytes(), StandardCharsets.UTF_8)
Spring Boot 项目额外注意
Spring Boot 默认禁用模块路径支持(除非显式配置 spring.main.web-application-type=none 并手动启用 JPMS)。若强行开启模块化,ClassPathResource 仍可用,但必须:
- 确保资源路径传入时不带前导斜杠(如
"config/app.yaml",而非"/config/app.yaml") - 禁止调用
resource.getFile();只用resource.getInputStream() - YAML/Properties 文件推荐交由
@ConfigurationProperties或YamlPropertySourceLoader自动加载,避开手动流操作











