cen*_*cen 16 java java-platform-module-system java-9
到目前为止,直到非模块化的java,你只需要放入一个文件,src/main/java/resources
确保它在classpath中,然后加载它
file = getClass().getClassLoader().getResourceAsStream("myfilename");
Run Code Online (Sandbox Code Playgroud)
来自类路径中的任何位置.
现在有了模块,情节变浓了.
我的项目设置如下:
module playground.api {
requires java.base;
requires java.logging;
requires framework.core;
}
Run Code Online (Sandbox Code Playgroud)
配置文件放在里面src/main/resources/config.yml
.
项目运行
java -p target/classes:target/dependency -m framework.core/com.framework.Main
Run Code Online (Sandbox Code Playgroud)
由于主类不在我自己的项目中,而是在外部框架模块中,因此无法看到config.yml
.现在的问题是,有没有办法以某种方式将我的配置文件放入模块或打开它?我是否必须更改框架上游加载文件的方式?
我尝试在module-info中使用"exports"或"opens",但它想要一个包名,而不是文件夹名.
如何以最佳实用的方式实现这一点,以便它可以像Java 8一样工作,并尽可能少地进行更改?
// 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)
Run Code Online (Sandbox Code Playgroud)
请参见下面的工作示例。
鉴于:
.
??? FrameworkCore
? ??? src
? ??? FrameworkCore
? ??? com
? ? ??? framework
? ? ??? Main.java
? ??? module-info.java
??? PlaygroundApi
??? src
??? PlaygroundApi
??? com
? ??? playground
? ??? api
? ??? App.java
??? config.yml
??? module-info.java
Run Code Online (Sandbox Code Playgroud)
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<Module> 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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后您将启动
java --module-path ./FrameworkCore/target/classes:./PlaygroundApi/target/classes \
--add-modules FrameworkCore,PlaygroundApi \
com.framework.Main
Run Code Online (Sandbox Code Playgroud)
要克隆此示例: git clone https://github.com/j4n0/SO-46861589.git
在使用该java
命令启动应用程序时,如下所示: -
java -p target/classes:target/dependency -m framework.core/com.framework.Main
Run Code Online (Sandbox Code Playgroud)
您正在使用选项-p
aternate 指定模块路径,该选项--module-path
将查找目标/类和模块的目标/依赖项.
另外,使用-m
alternate来--module
指定要使用名称解析的初始模块,framework.core
并使用主类构造模块图以明确地执行列出com.framework.Main
.
现在,这里的问题似乎是模块framework.core
没有 requires
或读取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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5946 次 |
最近记录: |