如何在 Java 9 中使用类加载器访问资源

Posted

技术标签:

【中文标题】如何在 Java 9 中使用类加载器访问资源【英文标题】:How to access resource using class loader in Java 9 【发布时间】:2018-07-23 22:41:31 【问题描述】:

我在 Eclipse 中有一个 gradle 项目。这是我的项目的结构

我在 scr/main/resources/css 中有 css 资源 styleclass.css。首先,我尝试使用

访问它
scene.getStylesheets().add("css/styleclass.css"); 

但是我收到了警告 resource not found. 我也通过删除 module-info.java 文件进行了尝试。但结果是一样的。

然后我用

试了一下
String urlString = ComboBoxStyling.class.getClassLoader().getResource("css/styleclass.css").toExternalForm();

问题是,如果我删除 moduele-info.java 并应用样式表,这条线就可以工作。但是module-info.java 我得到空指针异常。

我知道的不多,但至少我知道类加载器在 Java 9 中发生了变化。那么我怎样才能在 Java 9 中做同样的事情。我的 module-info.java 文件包含以下内容

module pk.training.basit 
    exports pk.training.basit;
    requires transitive javafx.controls;

感谢和问候

巴斯特·马哈茂德·艾哈迈德

【问题讨论】:

资源已被封装,因此无法通过 ClassLoader API 找到。我假设 ComboBoxStyling.class..getResource("/css/styleclass.css") 将起作用 - 请注意前导斜杠,以便相对于模块的根位置找到它,而不是相对于 ComboBoxStyling.class 在这种情况下。 是的,这是工作:) @Alan Bateman 发表您的答案,以便我接受 ***.com/questions/46861589/… 【参考方案1】:

来自ClassLoader.getResourceJavaDoc:

命名模块中的资源受 Module.getResourceAsStream 指定的封装规则的约束。另外,除了资源名称以“.class”结尾的特殊情况外,该方法只会在无条件打开包的情况下查找命名模块包中的资源(即使该方法的调用者在同一模块作为资源)。

所以,要解决你的问题,你应该打开包css

module pk.training.basit 
    exports pk.training.basit;
    requires transitive javafx.controls;
    opens css;

【讨论】:

最初的问题似乎是代码试图找到自己的资源。 ClassLoader API 是错误的 API。将代码更改为在模块中的类上调用 getResource 后,它应该可以正常工作,无需打开任何包。 @AlanBateman 我只是回答了 OP 的要求。如果他有 200 个 getClassLoader().getResource() 的位置怎么办?所以他可以只添加一行代码,而不是改变那 200 个地方。【参考方案2】:

您应该将您的 css 与使用它的类放在同一个包中,然后使用 Class.getResource 使用相对路径访问它。

src/main/java:
  pk.training.basit
    ComboBoxStyling.java

src/main/resources:
  pk.training.basit
    ComboBoxStyling.css

然后在源码中:

scene.getStylesheets().add(
  ComboBoxStyling.class.getResource("ComboBoxStyling.css").toExternalForm());

个人觉得最好还是把css和class放在同一个目录下,然后配置gradle这样就可以占用src/main目录下的资源了。它允许拥有类似于其他 GUI 产品 (Angular) 的架构,它将屏幕的所有资源(包括源代码)放在同一目录中,例如 FXML 文件,如果你有的话。

【讨论】:

以上是关于如何在 Java 9 中使用类加载器访问资源的主要内容,如果未能解决你的问题,请参考以下文章

面试题思考:如何编写自己的类加载器

JAVA实现代码热更新

高级特性- 安全

类加载器的双亲委派及打破双亲委派

从零开始手写Tomcat的教程8节----加载器

Java的类加载器