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