首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Java 9中加载类和资源

在Java 9中加载类和资源
EN

Stack Overflow用户
提问于 2017-07-18 12:25:08
回答 3查看 13.2K关注 0票数 47

我读过本文是关于InfoQ的引用Reinhold的话:

对于Java运行时,开发人员仍然可以使用Java 9中的Java类路径来搜索类和资源文件。只是使用Java 9的模块,开发人员不再需要类路径。

所以现在我的问题是:正确的Java 9执行上面列出的任务的方法是什么?您如何动态加载图像(缺少对相关路径的修改)?

更有趣的是,如何检查类是否可用并动态作出决定(例如,检查Jackson是否可用,如果可用,则用于JSON序列化,如果不使用其他东西)?

本文还提到Spring已经支持Java 9,Spring肯定会执行很多动态加载。所以,也许有人知道我可以看的Spring代码的主要部分?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-07-18 17:50:07

首先,为了澄清事实,我既没有说,也没有写上面引述的文字。我绝不会这么说的。这只是有关出版物的草率报道。

在Java 9中理解类加载和资源查找最重要的一点是,在基本级别上,它们没有改变。通过调用Class::forNameClassClassLoader类中的各种getResource*方法,您可以以与往常相同的方式搜索类和资源,而不管代码是从类路径加载还是从模块路径加载。仍然有三个内置的类加载器,就像JDK 1.2中的那样,它们具有相同的委托关系。因此,许多现有的代码都是开箱即用的。

正如9月261中所指出的,有一些细微之处:内置类加载器的具体类型已经改变,以前由引导类加载器加载的类现在由平台类加载器加载,以提高安全性。假设内置类加载器是URLClassLoader,或者类由引导类加载器加载的现有代码,因此可能需要进行小的调整。

最后一个重要的区别是模块中的非类文件资源在默认情况下是封装的,因此是open。要从自己的模块加载资源,最好使用ClassModule中的资源查找方法,它们可以定位模块中的任何资源,而不是ClassLoader中的资源,后者只能在模块的open包中定位非类文件资源。

票数 96
EN

Stack Overflow用户

发布于 2017-07-18 16:03:46

[编辑:这个答案是在马克的权威答案之前写的。我已经修改了我的版本,以提供一个简单的例子,可用的论GitHub。]

按照这段视频,Java9中的类加载保持不变。

举个例子,假设我们有:

  • 包含包example.jar中的图像的net.codetojoy.example.resources
  • 为了增强jar,net.codetojoy.example.Composer是公开的(并在适用的情况下导出)
  • 一个简单的App类,它使用example.jar作为库并尝试从它加载图像。

App中的相关代码

代码语言:javascript
复制
static InputStream getResourceAsStream(String resource) 
    throws Exception {

    // Load net/codetojoy/example/resource/image.jpg
    // Assume net.codetojoy.example.Composer is public/exported
    // resource is 'resource/image.jpg'

    InputStream result = Composer.class.getResourceAsStream(resource);

    return result;
}   

下面是JDK 9中example.jar的几个例子:

老式的、非模块化的

如果example.jar不是一个模块,那么代码就可以工作了。类加载保持不变。

带有开放式封装的模块

在本例中,这是module-info.java文件:

代码语言:javascript
复制
module net.codetojoy.example {
    // export the Composer class
    exports net.codetojoy.example;

    // image is available
    opens net.codetojoy.example.resources;
}

在这种情况下,图像可以由客户端加载,因为包是打开的。

没有开放包的模块

在这种情况下,module-info.java是:

代码语言:javascript
复制
module net.codetojoy.example {
    // export the Composer class
    exports net.codetojoy.example;

    // package not opened: image not available
    // opens net.codetojoy.example.resources;
}

在这种情况下,由于强大的封装,无法加载映像:模块通过不打开包来保护映像。

全源在GitHub上.

票数 6
EN

Stack Overflow用户

发布于 2021-06-05 18:53:18

除了现有的答案之外,我还想举例说明不同资源目录名称的非类文件资源的封装规则。

getResourceAsStream的规范说,如果包名是从它的名称派生出来的,那么资源就会被封装。

因此,如果是资源的目录名不是有效的Java标识符,则不会封装它。这意味着,如果一个模块的资源位于一个名为dir-1的目录下(它的名称中包含一个非有效字符- ),那么它始终可以从模块外部访问。

下面是两个Java模块(GitHub中的源代码)的示例。模块1由以下资源文件组成:

代码语言:javascript
复制
├── dir-3
│   └── resource3.txt
├── dir1
│   └── resource1.txt
├── dir2
│   └── resource2.txt
└── root.txt

module-info.java

代码语言:javascript
复制
module module_one {
  opens dir1;
}

模块2在module-info.java中要求模块1

代码语言:javascript
复制
module module_two {
  requires module_one;
}

并有一个用于加载各种资源文件的示例主类:

代码语言:javascript
复制
package module2;

import java.io.IOException;

public class Main {
  public static void main(String[] args) throws IOException {
    loadResource("root.txt", "From module's root directory");
    loadResource("dir1/resource1.txt", "From opened package `dir1`");
    loadResource("dir2/resource2.txt", "From internal package `dir2`");
    loadResource("dir-3/resource3.txt", "From directory `dir-3` with non-Java name");
  }

  public static void loadResource(String name, String comment) throws IOException {
    // module2 application class loader
    final var classLoader = Main.class.getClassLoader();
    try (var in = classLoader.getResourceAsStream(name)) {
      System.out.println();
      System.out.println("// " + comment);
      System.out.println(name + ": " + (in != null));
    }
  }
}

运行上面的类提供以下输出:



代码语言:javascript
复制
// From module's root directory
root.txt: true

// From opened package `dir1`
dir1/resource1.txt: true

// From internal package `dir2`
dir2/resource2.txt: false

// From directory `dir-3` with non-Java name
dir-3/resource3.txt: true

如您所见,没有封装根目录和dir-3目录中的资源文件,因此Module2可以加载它们。

封装了包dir1,但无条件地打开了。模块2也可以加载它。

封装了包dir2,而不是打开它。模块2无法加载它。

请注意,模块2不能在dir1dir2目录下包含它们自己的资源,因为它们已经封装在模块1中。如果尝试添加dir1,您将得到以下错误:

代码语言:javascript
复制
Error occurred during initialization of boot layer
java.lang.LayerInstantiationException: Package dir1 in both module module_one and module module_two

这是一个供参考的天桥相关问题

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45166757

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档