从外部模块访问资源文件

16 浏览
0 Comments

从外部模块访问资源文件

到目前为止,在非模块化的Java中,您只需将文件放在src/main/java/resources中,确保它在类路径中,然后使用以下代码在类路径的几乎任何位置加载它:

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中一样工作,并尽可能少地进行更改?

0
0 Comments

在使用java命令启动应用程序时,您可以通过以下方式访问资源文件:-

java -p target/classes:target/dependency -m framework.core/com.framework.Main 

  • 您使用-p选项指定了模块路径,该选项是--module-path的替代,它将在target/classestarget/dependency中查找模块。
  • 同时,使用-m选项作为--module的替代,指定了要解析的初始模块,名称为framework.core,并将主类com.framework.Main明确列在要执行的模块图中。

现在,问题似乎是模块framework.core没有requires或读取playground.api模块,因此模块图不包括包含实际资源config.yml的所需模块。

建议的,在启动期间列出模块解析输出的好方法是使用--show-module-resolution选项。


我只是天真地尝试打开src/main/resources,当然无法编译

由于您的模块中的资源位于根级别,因此它未封装,不需要打开或导出给任何其他模块。

在您的情况下,您只需要确保模块playground.api出现在模块图中,然后该资源将对应用程序可访问。要指定要解析的根模块以及初始模块,可以使用--add-modules选项。


因此,解决方案为:

java --module-path target/classes:target/dependency 
     --module framework.core/com.framework.Main
     --add-modules playground.api
     --show-module-resolution

0
0 Comments

当在命名模块中运行时,ClassLoader的getResource方法具有非常令人惊讶的行为。getResourceAsStream方法也同样有问题。我在升级应用程序到命名模块时遇到了这个问题。

如果你的代码在一个命名模块中,并且通过ClassLoader的getResource方法访问资源,那么该资源的包必须无条件地被打开。否则,即使资源位于同一个模块中,你也无法检索到该资源。

这与Class的getResource方法的行为不同-请注意区别。Class的getResource方法是直接的,没有这个令人讨厌的意外情况。

关于getResource的所有说法也适用于getResourceAsStream方法。

因此,我建议始终使用Class上的getResource方法,而不是ClassLoader上的方法。

还可以参考我对Class.getResource和ClassLoader.getResource之间的区别是什么的回答。

0
0 Comments

问题的出现原因:

问题是在一个模块中访问另一个模块中的资源文件时遇到的。在给定的示例中,有两个模块:FrameworkCore和PlaygroundApi。FrameworkCore模块想要访问PlaygroundApi模块中的config.yml文件。然而,由于模块的封装性,FrameworkCore模块无法直接访问PlaygroundApi模块中的资源文件。

解决方法:

为了解决这个问题,可以使用以下几种方法来访问外部模块的资源文件:

1. 如果知道资源文件的名称,可以使用ClassLoader的getSystemResources()方法来扫描模块路径,获取资源文件的URL。示例代码如下:

ClassLoader.getSystemResources(resourceName)

2. 如果知道包含资源文件的类,可以使用Class.forName()方法来获取资源文件的输入流。示例代码如下:

Class.forName(className).getResourceAsStream(resourceName)

3. 如果知道包含资源文件的模块名称,可以使用ModuleLayer.boot().findModule()方法来获取模块并获取资源文件的输入流。示例代码如下:

ModuleLayer.boot().findModule(moduleName).getResourceAsStream(resourceName)

以上是解决访问外部模块资源文件的方法。

文章完整内容如下:

在Java应用程序中,有时候需要在一个模块中访问另一个模块中的资源文件。然而,在模块的封装性限制下,直接访问外部模块的资源文件可能会遇到问题。下面我们将介绍一些访问外部模块资源文件的方法。

首先,可以使用ClassLoader的getSystemResources()方法来扫描模块路径,获取资源文件的URL。示例代码如下:

ClassLoader.getSystemResources(resourceName)

其次,如果知道包含资源文件的类,可以使用Class.forName()方法来获取资源文件的输入流。示例代码如下:

Class.forName(className).getResourceAsStream(resourceName)

另外,如果知道包含资源文件的模块名称,可以使用ModuleLayer.boot().findModule()方法来获取模块并获取资源文件的输入流。示例代码如下:

ModuleLayer.boot().findModule(moduleName).getResourceAsStream(resourceName)

通过以上方法,我们可以解决在一个模块中访问另一个模块的资源文件的问题。

举个例子来说明,假设我们有两个模块:FrameworkCore和PlaygroundApi。FrameworkCore模块想要访问PlaygroundApi模块中的config.yml文件。我们可以使用上述方法来实现。

在FrameworkCore模块的Main.java文件中,我们可以使用ClassLoader的getSystemResources()方法来获取config.yml文件的URL,并通过URL的openStream()方法获取输入流,代码如下:

URL url = ClassLoader.getSystemResources("config.yml").nextElement();
InputStream is = url.openStream();
Main.read(is);

另外,我们也可以使用Class.forName()方法来获取资源文件的输入流,代码如下:

InputStream is = Class.forName("com.playground.api.App").getResourceAsStream("/config.yml");
Main.read(is);

还可以使用ModuleLayer.boot().findModule()方法来获取PlaygroundApi模块并获取资源文件的输入流,代码如下:

Optional<Module> specificModule = ModuleLayer.boot().findModule("PlaygroundApi");
specificModule.ifPresent(module -> {
    InputStream is = module.getResourceAsStream("config.yml");
    Main.read(is);
});

通过这些方法,我们可以在FrameworkCore模块中成功访问PlaygroundApi模块的资源文件。

在Java应用程序中,访问外部模块的资源文件可能会受到模块的封装性限制。为了解决这个问题,我们可以使用ClassLoader和Module API提供的方法来获取外部模块的资源文件。通过这些方法,我们可以轻松地在一个模块中访问另一个模块的资源文件,实现模块间的资源共享。

0