缺少 Maven Shade JavaFX 运行时组件
Maven Shade JavaFX runtime components are missing
我正在尝试使用 Maven 依赖项创建 JFX11 自包含 jar。从我所做的研究来看,似乎最好的方法是通过 maven shade 插件。但是,当我 运行 它时,我得到了这个错误:
错误:缺少 JavaFX 运行时间组件,运行 此应用程序需要
我不明白为什么会这样。我在搞什么鬼?有一个更好的方法吗?我也尝试过使用相同消息的 maven assembly 插件。
pom文件供参考
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Application</groupId>
<artifactId>Main</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpaceRunner</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>10</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>Application.Main</mainClass>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>
Application.Main
</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>Application.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2021 年 10 月更新
自 JavaFX 16 起,当 JavaFX 不在模块路径上 运行 时会显示警告,这是 uber/fat jar 的情况:
$ java -jar myFatJar-1.0-SNAPSHOT.jar
Oct 02, 2021 1:45:21 PM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @14c24f4c'
此外,您会收到来自阴影插件本身的警告:
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
虽然最初可以忽略这些警告,但这是有原因的。
如本文所述CSR:
JavaFX is built and distributed as a set of named modules, each in its own modular jar file, and the JavaFX runtime expects its classes to be loaded from a set of named javafx.* modules, and does not support loading those modules from the classpath.
并且:
when the JavaFX classes are loaded from the classpath, it breaks encapsulation, since we no longer get the benefit of the java module system.
因此,即使这个被广泛接受的答案也解释了如何在 Maven 项目上创建 uber/fat jar,不鼓励使用它,以及其他现代替代方案来分发您的应用程序,例如 jlink
, jpackage
或 native-image
, 应使用 .
原始答案
这 解释了为什么 fat/uber jar 在 JavaFX 11 上失败。简而言之:
This error comes from sun.launcher.LauncherHelper in the java.base module. The reason for this is that the Main app extends Application and has a main method. If that is the case, the LauncherHelper will check for the javafx.graphics
module to be present as a named module. If that module is not present, the launch is aborted.
并且已经提出了 Gradle 的修复方案。
对于 Maven,解决方案完全相同:提供一个不从 Application
.
扩展的新主 class
您的 application
包中将有新的 class(错误名称):
// NewMain.java
public class NewMain {
public static void main(String[] args) {
Main.main(args);
}
}
和您现有的 Main
class,原样:
//Main.java
public class Main extends Application {
@Override
public void start(Stage stage) {
...
}
public static void main(String[] args) {
launch(args);
}
}
现在您需要修改您的 pom 并为不同的插件设置主 class:
<mainClass>application.NewMain</mainClass>
特定于平台的 Fat jar
最后,使用 shade 插件,您将在您的机器上生成一个 fat jar。
这意味着,到目前为止,您的 JavaFX 依赖项正在使用独特的 classifier。例如,如果您在 Windows 上,Maven 将在内部使用 win
classifier。这具有仅包含 Windows.
的本机库的效果
所以你正在使用:
- org.openjfx:javafx-controls:11
- org.openjfx:javafx-controls:11:win
- org.openjfx:javafx-graphics:11
- org.openjfx:javafx-graphics:11:win <-- 这包含 Windows
的本机 dll
- org.openjfx:javafx-base:11
- org.openjfx:javafx-base:11:win
现在,如果您生成 fat jar,您将捆绑所有这些依赖项(以及项目中的其他常规第三方依赖项),并且您将能够 运行 您的项目如下:
java -jar myFatJar-1.0-SNAPSHOT.jar
虽然这很好,但是如果你想分发你的 jar,请注意这个 jar 不是 跨平台的,它只能在你的平台上工作,在这种情况 Windows.
跨平台 Fat Jar
有一个解决方案可以生成可以分发的跨平台 jar:包括其他平台的其余本机库。
这很容易完成,因为您只需要包括三个平台的图形模块依赖项:
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>win</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>linux</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>mac</classifier>
</dependency>
</dependencies>
尺码
这种方法有一个主要问题:大小。正如您在另一个 中看到的那样,如果您使用 WebView 控件,由于 WebKit 本机库,您将捆绑大约 220 MB。
我正在尝试使用 Maven 依赖项创建 JFX11 自包含 jar。从我所做的研究来看,似乎最好的方法是通过 maven shade 插件。但是,当我 运行 它时,我得到了这个错误:
错误:缺少 JavaFX 运行时间组件,运行 此应用程序需要
我不明白为什么会这样。我在搞什么鬼?有一个更好的方法吗?我也尝试过使用相同消息的 maven assembly 插件。
pom文件供参考
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Application</groupId>
<artifactId>Main</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpaceRunner</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>10</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>Application.Main</mainClass>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>
Application.Main
</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>Application.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2021 年 10 月更新
自 JavaFX 16 起,当 JavaFX 不在模块路径上 运行 时会显示警告,这是 uber/fat jar 的情况:
$ java -jar myFatJar-1.0-SNAPSHOT.jar
Oct 02, 2021 1:45:21 PM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @14c24f4c'
此外,您会收到来自阴影插件本身的警告:
[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.
虽然最初可以忽略这些警告,但这是有原因的。
如本文所述CSR:
JavaFX is built and distributed as a set of named modules, each in its own modular jar file, and the JavaFX runtime expects its classes to be loaded from a set of named javafx.* modules, and does not support loading those modules from the classpath.
并且:
when the JavaFX classes are loaded from the classpath, it breaks encapsulation, since we no longer get the benefit of the java module system.
因此,即使这个被广泛接受的答案也解释了如何在 Maven 项目上创建 uber/fat jar,不鼓励使用它,以及其他现代替代方案来分发您的应用程序,例如 jlink
, jpackage
或 native-image
, 应使用 .
原始答案
这
This error comes from sun.launcher.LauncherHelper in the java.base module. The reason for this is that the Main app extends Application and has a main method. If that is the case, the LauncherHelper will check for the
javafx.graphics
module to be present as a named module. If that module is not present, the launch is aborted.
并且已经提出了 Gradle 的修复方案。
对于 Maven,解决方案完全相同:提供一个不从 Application
.
您的 application
包中将有新的 class(错误名称):
// NewMain.java
public class NewMain {
public static void main(String[] args) {
Main.main(args);
}
}
和您现有的 Main
class,原样:
//Main.java
public class Main extends Application {
@Override
public void start(Stage stage) {
...
}
public static void main(String[] args) {
launch(args);
}
}
现在您需要修改您的 pom 并为不同的插件设置主 class:
<mainClass>application.NewMain</mainClass>
特定于平台的 Fat jar
最后,使用 shade 插件,您将在您的机器上生成一个 fat jar。
这意味着,到目前为止,您的 JavaFX 依赖项正在使用独特的 classifier。例如,如果您在 Windows 上,Maven 将在内部使用 win
classifier。这具有仅包含 Windows.
所以你正在使用:
- org.openjfx:javafx-controls:11
- org.openjfx:javafx-controls:11:win
- org.openjfx:javafx-graphics:11
- org.openjfx:javafx-graphics:11:win <-- 这包含 Windows 的本机 dll
- org.openjfx:javafx-base:11
- org.openjfx:javafx-base:11:win
现在,如果您生成 fat jar,您将捆绑所有这些依赖项(以及项目中的其他常规第三方依赖项),并且您将能够 运行 您的项目如下:
java -jar myFatJar-1.0-SNAPSHOT.jar
虽然这很好,但是如果你想分发你的 jar,请注意这个 jar 不是 跨平台的,它只能在你的平台上工作,在这种情况 Windows.
跨平台 Fat Jar
有一个解决方案可以生成可以分发的跨平台 jar:包括其他平台的其余本机库。
这很容易完成,因为您只需要包括三个平台的图形模块依赖项:
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>win</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>linux</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>mac</classifier>
</dependency>
</dependencies>
尺码
这种方法有一个主要问题:大小。正如您在另一个