我正在尝试使用 maven 依赖项创建一个 JFX11 自包含 jar。从我所做的研究来看,似乎最好的方法是通过 maven shade 插件。但是,当我运行它时,我得到了这个错误:
错误:JavaFX 运行时组件丢失,是运行此应用程序所必需的
我不明白为什么会这样。我在搞砸什么?有一个更好的方法吗?我也尝试过使用相同消息的 maven 程序集插件。
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
,应该使用。
原始答案
这个 answer解释了为什么胖/ super 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
扩展的新主类。
你的 application
包中会有新的类(坏名):
// NewMain.java
public class NewMain {
public static void main(String[] args) {
Main.main(args);
}
}
和你现有的 Main
类一样:
//Main.java
public class Main extends Application {
@Override
public void start(Stage stage) {
...
}
public static void main(String[] args) {
launch(args);
}
}
现在你需要修改你的 pom 并为不同的插件设置你的主类:
<mainClass>application.NewMain</mainClass>
平台特定的 Fat jar
最后,您将使用 shade 插件在您的机器上生成一个 fat jar 子,。
这意味着,到目前为止,您的 JavaFX 依赖项使用的是唯一的分类器。例如,如果您在 Windows 上,Maven 将在内部使用 win
分类器。这样做的效果是只包含 Windows 的 native 库。
所以你正在使用:
- org.openjfx:javafx-controls:11
- org.openjfx:javafx-controls:11:win
- org.openjfx:javafx-graphics:11
- org.openjfx:javafx-graphics:11:win <-- 这包含 Windows 的 native 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:包含其他平台的其余 native 库。
这很容易做到,因为您只需要包含三个平台的图形模块依赖项:
<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>
尺寸
这种方法有一个主要问题:尺寸。正如你在另一个 answer 中看到的那样,如果您使用 WebView 控件,由于 WebKit 原生库,您将捆绑大约 220 MB。
关于java - 缺少 Maven Shade JavaFX 运行时组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52653836/