Java 9拼图 – 从外部模块访问资源文件
到目前为止,非模块化的java,你只需将文件放在src/main/java/resources
确保它在classpath中,然后加载它
file = getClass().getClassLoader().getResourceAsStream("myfilename");
来自类路径中的任何位置。
现在有了模块,情节变浓了。
我的项目设置如下:
module playground.api { requires java.base; requires java.logging; requires framework.core; }
配置文件放在src/main/resources/config.yml
。
项目运行
java -p target/classes:target/dependency -m framework.core/com.framework.Main
由于主类不在我自己的项目中,而是在外部框架模块中,因此无法看到config.yml
。 现在的问题是,有没有办法以某种方式将我的配置文件放入模块或打开它? 我是否必须更改框架上游加载文件的方式?
我尝试在module-info中使用“exports”或“opens”,但它想要一个包名,而不是文件夹名。
如何以最佳实用的方式实现这一点,以便它可以像Java 8一样工作,并尽可能少地进行更改?
当您使用java
命令启动应用程序时,如下所示: –
java -p target/classes:target/dependency -m framework.core/com.framework.Main
-
您正在使用
-p
aternate选项为--module-path
-p
模块--module-path
,该选项将查找目标/类和模块的目标/依赖项 。 -
除此之外,使用
-m
alternate for--module
指定要使用名称framework.core
解析的初始模块,并使用主类构造模块图,以明确地将其列为com.framework.Main
。
现在,问题似乎是模块framework.core
不需要或读取playground.api
模块,因为模块图不包含由实际资源config.yml
组成的所需模块。
正如@Alan所建议的 ,在启动期间列出模块分辨率输出的一种好方法是使用--show-module-resolution
选项。
我只是天真地尝试打开src / main / resources,不编译ofc
由于模块中的资源位于根级别 ,因此它不会被封装 ,也不需要打开或导出到任何其他模块。
在您的情况下,您只需要确保模块playground.api
最终在模块图中,然后应用程序可以访问该资源。 要指定除初始模块之外要解析的根模块,可以使用--add-modules
选项。
因此,为您工作的整体解决方案以及一些调试应该是:
java --module-path target/classes:target/dependency --module framework.core/com.framework.Main --add-modules playground.api --show-module-resolution
// to scan the module path ClassLoader.getSystemResources(resourceName) // if you know a class where the resource is Class.forName(className).getResourceAsStream(resourceName) // if you know the module containing the resource ModuleLayer.boot().findModule(moduleName).getResourceAsStream(resourceName)
请参阅下面的工作示例。
鉴于:
. ├── FrameworkCore │ └── src │ └── FrameworkCore │ ├── com │ │ └── framework │ │ └── Main.java │ └── module-info.java └── PlaygroundApi └── src └── PlaygroundApi ├── com │ └── playground │ └── api │ └── App.java ├── config.yml └── module-info.java
Main.java
可能是
package com.framework; import java.io.*; import java.net.URL; import java.util.Optional; import java.util.stream.Collectors; public class Main { public static void main( String[] args ) { // load from anywhere in the modulepath try { URL url = ClassLoader.getSystemResources("config.yml").nextElement(); InputStream is = url.openStream(); Main.read(is); } catch (IOException e) { throw new RuntimeException(e); } // load from the the module where a given class is try { InputStream is = Class.forName("com.playground.api.App").getResourceAsStream("/config.yml"); Main.read(is); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } // load from a specific module Optional specificModule = ModuleLayer.boot().findModule("PlaygroundApi"); specificModule.ifPresent(module -> { try { InputStream is = module.getResourceAsStream("config.yml"); Main.read(is); } catch (Exception e) { throw new RuntimeException(e); } }); } private static void read(InputStream is) { String s = new BufferedReader(new InputStreamReader(is)).lines().collect(Collectors.joining("\n")); System.out.println("config.yml: " + s); } }
而你会发射
java --module-path ./FrameworkCore/target/classes:./PlaygroundApi/target/classes \ --add-modules FrameworkCore,PlaygroundApi \ com.framework.Main
要克隆此示例: git clone https://github.com/j4n0/SO-46861589.git