如何从其他Maven模块获取resources资源?Jar环境下稳定实现及问题解析
为什么你的代码返回target/classes而不是resources目录?
这其实是Maven的默认构建行为导致的:Maven在执行compile阶段时,会自动把src/main/resources目录下的所有文件复制到target/classes目录(这个目录是当前模块的类路径根目录)。同时,编译后的class文件也会放在这里。
类加载器在运行时(不管是IDE中运行还是打包成Jar后),只会从类路径加载资源,而不会去读取源码目录里的resources。所以你用getResource()拿到的路径,自然是构建后类路径里的位置,也就是target/classes下的资源。而且等你把模块打包成Jar后,resources目录根本不会出现在Jar里——里面的资源会直接放在Jar的根目录(或者对应子路径),连target/classes这个路径都不存在了。
另外,你用getFile()的方式还有个大问题:如果是Jar包环境,资源是Jar内部的条目,不是文件系统上的独立文件,getFile()会返回类似file:/xxx/your-module.jar!/resource.txt的字符串,直接用这个路径去读文件肯定会报错。
稳定可用的跨模块资源访问方案(支持Jar环境)
要实现跨模块资源访问,核心是依赖正确配置+用流的方式读取资源,具体步骤如下:
1. 先确保模块间的Maven依赖配置正确
假设你有两个子模块:module-a(存放resource.txt)和module-b(需要读取这个资源),那么在module-b的pom.xml里必须引入module-a的依赖:
<dependency> <groupId>你的项目groupId</groupId> <artifactId>module-a</artifactId> <version>项目版本号</version> </dependency>
这样module-b的类加载器才能找到module-a里的资源。
2. 用类加载器的流方式读取资源(推荐)
不要用getFile(),改用getResourceAsStream()来获取输入流,这种方式在IDE运行和Jar包环境下都能稳定工作:
// 在module-b的代码中,读取module-a里的resource.txt try (InputStream inputStream = ClassFromModuleA.class.getClassLoader() .getResourceAsStream("resource.txt")) { if (inputStream == null) { throw new RuntimeException("找不到resource.txt资源"); } // 把流转换成字符串(示例) String content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); System.out.println(content); } catch (IOException e) { e.printStackTrace(); }
如果你的资源在resources的子目录下(比如resources/config/resource.txt),只需要把路径改成"config/resource.txt"即可。
3. 另一种方式:用Class类的getResourceAsStream()
如果资源和ClassFromModuleA在同一个包下,或者你想用相对路径,可以直接用类对象来获取:
// 绝对路径(从类路径根开始,前面加/) InputStream inputStream = ClassFromModuleA.class.getResourceAsStream("/resource.txt"); // 如果resource.txt和ClassFromModuleA在同一个包下,比如都在com/example目录,就可以直接写文件名 // InputStream inputStream = ClassFromModuleA.class.getResourceAsStream("resource.txt");
Jar环境下的额外注意事项
- 绝对不要依赖文件系统路径来读取资源,Jar里的资源不是独立文件,必须用流的方式处理。
- 如果是读取配置文件(比如
properties),可以直接用Properties类的load()方法加载流:
Properties props = new Properties(); try (InputStream is = ClassFromModuleA.class.getClassLoader().getResourceAsStream("config.properties")) { props.load(is); String value = props.getProperty("key"); } catch (IOException e) { e.printStackTrace(); }
内容的提问来源于stack exchange,提问作者Junkwin

