TL;DR:
确保 JavaFX 被解析为命名模块。
-
非模块化应用:
java --module-path <path-to-fx> --add-modules <fx-modules> ...
-
模块化应用:
java --module-path <path> --module <main-module>/<main-class> [args...]
<path> 包括您的模块以及 JavaFX。
-
使用包含 JavaFX 的 JDK 发行版(有关更多信息,请参阅下面的答案)。可能还需要使用--add-modules。
背景
此警告与 Java 9 中引入的 Java 平台模块系统 (JPMS) 有关。如果您不熟悉模块,我建议您阅读Understanding Java 9 Modules 以获得简要概述。
JPMS 出现了模块路径,现在它与类路径一起存在。当类从类路径加载时,它们成为所谓的未命名模块的一部分。而模块路径上的类包含在模块中,因此被“加载到”命名模块中。一个命名的模块可能是也可能不是自动的,这分别取决于它是否有module-info 描述符。
警告
JavaFX 仅支持作为命名模块加载。换句话说,JavaFX 只支持从模块路径加载,不支持从类路径加载。从版本 9 开始,当框架模块化时,这一直是隐含的。但是现在,从版本 16 开始,如果 JavaFX 检测到它是从类路径加载的(即在 未命名的模块中),则会发出警告。见JDK-8256362。
解决方案
解决方案是确保从模块路径加载 JavaFX 并解析为命名模块。注意 JavaFX 由七个模块组成,如 its documentation 所示。
您如何确保将 JavaFX 解析为命名模块可能取决于您的环境(例如,非模块化与模块化应用程序、外部 JavaFX SDK 等)。下面的示例都使用命令行来显示如何设置所需的参数。但是,如果您使用的是 IDE(例如 NetBeans、IntelliJ、Eclipse)和/或构建工具(例如 Maven、Gradle)并且不确定在哪里设置这些参数,请查看Getting Started with JavaFX 11+。
请注意,Gradle 和 Maven 都有插件,可以更轻松地使用 JavaFX(即它们为您处理所有配置)。
非模块化应用
如果您的代码是非模块化的,那么您就没有module-info 描述符。这意味着将 JavaFX 添加到模块路径是不够的;您还必须强制 Java 解析 JavaFX 模块。这可以通过--add-modules 参数来完成。
例如:
java --module-path <path-to-fx> --add-modules javafx.controls ...
请注意,我只在 --add-modules 参数中包含了 javafx.controls 模块。这是因为它需要 javafx.base 和 javafx.graphics 模块,这意味着它们将被隐式拉入。
如果您需要其他模块,则还需要将它们包含在 --add-modules 参数中,用逗号分隔。
另外,请注意,在这种情况下,可以将您的代码和其他非模块化依赖项放在类路径上。重要的部分是 JavaFX 是从模块路径加载的。
模块化应用
如果您的代码是模块化的,那么您将拥有module-info 描述符。该描述符将具有必要的requires 指令。在这种情况下,您不再需要使用--add-modules,但您需要确保通过--module 作为模块启动您的应用程序。
例如:
module app {
// transitively requires javafx.base and javafx.graphics
requires javafx.controls;
// export javafx.application.Application implementation's package
// to at least javafx.graphics
exports com.example.app to javafx.graphics;
}
java --module-path <path> --module app/com.example.app.Main [args...]
请注意,您不仅需要将 JavaFX 放在模块路径上,还需要将您自己的模块。
使用包含 JavaFX 的 JDK 发行版
从 Java 11 开始,JavaFX 不再包含在 Oracle 提供的 JDK 中。但是甲骨文并不是唯一的基于 OpenJDK 的 Java 供应商。有些供应商提供包含 JavaFX 的 JDK 发行版。其中至少有两个是:
当 JavaFX 包含在 JDK 中时,它现在像所有其他 Java 模块一样成为运行时映像的一部分(例如 java.base)。这意味着它将自动加载为 命名模块,您不再需要手动将 JavaFX 放在模块路径上。但是,如果您的应用程序是非模块化的,那么您可能仍需要使用 --add-modules(不确定)。
部署
当您要部署 JavaFX 应用程序时,在运行时映像中包含 JavaFX 可能是最简单的方法。您可以使用 jlink / jpackage 工具来执行此操作。这可以通过包含 JavaFX 的 JDK 或外部 JavaFX SDK 来完成。但是,如果您使用后者,请确保在制作自定义运行时映像时使用 JMOD 文件(或使用来自 Maven Central 的 JavaFX JAR,其中嵌入了所需的本机代码)。
如果您的代码是非模块化的,那么您将创建一个包含 JavaFX(以及您的应用程序所需的所有其他非自动命名模块)的自定义运行时映像,然后配置 jpackage 以放置您的类路径上的代码(以及所有非模块化依赖项)。
忽略警告
据我所知,如果从类路径加载 JavaFX,当前 不会中断。这意味着另一种选择,至少目前是忽略警告。但是,我建议您至少将 JavaFX 放在模块路径上,如果您可以这样做而不会有太多麻烦的话。