多模块JavaFX maven项目打包问题
Multi-module JavaFX maven project packaging issue
这是尝试使用 maven 创建多模块 JavaFX 应用程序。
给定以下项目结构:
project
| pom1.xml
|_____ Word Generator (Folder)
| pom2.xml
|_____logic (folder)
| WordGenerator
|_____UI (folder)
| pom3.xml
|_____marty
| App
| PrimaryController
| SecondaryController
我们按照上述方案的顺序有以下 pom 文件结构:
pom1.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.games.marty</groupId>
<artifactId>words</artifactId>
<packaging>pom</packaging>
<version>0.1</version>
<modules>
<module>UI</module>
<module>Word Generator</module>
</modules>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
pom2.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>words</artifactId>
<groupId>org.games.marty</groupId>
<version>0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>word.generator</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.games.marty.logic.WordGenerator</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
pom3.xml
<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>
<artifactId>UI</artifactId>
<version>0.1</version>
<parent>
<artifactId>words</artifactId>
<groupId>org.games.marty</groupId>
<version>0.1</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>16</version>
</dependency>
<dependency>
<groupId>org.games.marty</groupId>
<artifactId>word.generator</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>16</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>org.games.marty.App</mainClass>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.games.marty.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
为了让 UI 能够访问 WordGenerator 逻辑,我们尝试构建应用程序的方法是对 package
pom1.xml 指令的结果进行 maven [=] 16=]
如前所述,我们得到上述错误:
Error: Could not find or load main class org.games.marty.App
Caused by: java.lang.NoClassDefFoundError: javafx/application/Application
据我所知,JavaFX 依赖项是通过 maven 安装的,应该可用但它们丢失了?
使用 maven-jar-plugin
通过 mvn package
打包是不够的
mvn package
,默认情况下只是打包你的应用代码的jar,不会包含所有的依赖库代码(这就是为什么依赖代码找不到的原因您尝试 运行 您的申请)。
您可以使用程序集打包您的应用程序代码和依赖库,如 How can I create an executable JAR with dependencies using Maven? 中所述,尽管这种方法并不是解决您问题的唯一方法。
您需要构建某种 运行时间图像
构建 运行time 图像的选项有很多,我不知道您的要求,所以我无法推荐您应该做什么。示例选项是:
- 您的 zip/tar 应用程序和单独目录中的库。
- 创建包含所有相关代码的单个 jar。
- 解决方案 1 或 2,加上打包的 JRE。
- 带有您的代码和库的 运行time 图像,它也仅使用您需要的 JRE 和 JavaFX 模块的自定义 运行time 部分(使用 jlink)。
- 3 或 4 的本地安装程序(使用 jpackage + 本地安装程序创建工具,例如 WIX、RPM、DEB 安装程序创建者)。
最后一种方法(本机安装程序)是我为大多数重要应用程序推荐的打包、分发和安装方法。
你需要研究如何做到这一点
要获得您的解决方案,您需要进行自己的研究,并且,一旦您选择了一种方法和工具集,如果您仍然遇到困难,您可以创建一个关于该方法实施的新问题。
相关资源
- How can I create an executable JAR with dependencies using Maven?
- openjfx Runtime images documentation
- maven shade plugin
- openjfx JavaFX maven plugin
- badass runtime plugin
- badass jlink plugin
- jlink guide
- jpackage script
- JEP 392: packaging tool
阴影罐警告
如果使用 maven shade 插件将所有 JavaFX 代码捆绑到一个 jar 中,当您 运行 来自 Java 16 的应用程序时,您将收到如下警告+:
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @28c71909'
这表明不支持这样的配置,并且可能(并且可能会)在未来和当前的 JavaFX 平台修订版中中断。因此,我不推荐包含 JavaFX 平台代码的阴影 jar,即使此类 jar 当前可能适用于您的部署。
JavaFX 11+ 被构建为用作一组模块。如果配置不 运行 模块路径之外的 JavaFX 平台而是 运行 类路径之外的平台代码(就像阴影 jar 那样),则不支持这些配置。
这是尝试使用 maven 创建多模块 JavaFX 应用程序。
给定以下项目结构:
project
| pom1.xml
|_____ Word Generator (Folder)
| pom2.xml
|_____logic (folder)
| WordGenerator
|_____UI (folder)
| pom3.xml
|_____marty
| App
| PrimaryController
| SecondaryController
我们按照上述方案的顺序有以下 pom 文件结构:
pom1.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.games.marty</groupId>
<artifactId>words</artifactId>
<packaging>pom</packaging>
<version>0.1</version>
<modules>
<module>UI</module>
<module>Word Generator</module>
</modules>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
pom2.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>words</artifactId>
<groupId>org.games.marty</groupId>
<version>0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>word.generator</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.games.marty.logic.WordGenerator</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
pom3.xml
<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>
<artifactId>UI</artifactId>
<version>0.1</version>
<parent>
<artifactId>words</artifactId>
<groupId>org.games.marty</groupId>
<version>0.1</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>16</version>
</dependency>
<dependency>
<groupId>org.games.marty</groupId>
<artifactId>word.generator</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>16</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>org.games.marty.App</mainClass>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.games.marty.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
为了让 UI 能够访问 WordGenerator 逻辑,我们尝试构建应用程序的方法是对 package
pom1.xml 指令的结果进行 maven [=] 16=]
如前所述,我们得到上述错误:
Error: Could not find or load main class org.games.marty.App
Caused by: java.lang.NoClassDefFoundError: javafx/application/Application
据我所知,JavaFX 依赖项是通过 maven 安装的,应该可用但它们丢失了?
使用 maven-jar-plugin
通过 mvn package
打包是不够的
mvn package
,默认情况下只是打包你的应用代码的jar,不会包含所有的依赖库代码(这就是为什么依赖代码找不到的原因您尝试 运行 您的申请)。
您可以使用程序集打包您的应用程序代码和依赖库,如 How can I create an executable JAR with dependencies using Maven? 中所述,尽管这种方法并不是解决您问题的唯一方法。
您需要构建某种 运行时间图像
构建 运行time 图像的选项有很多,我不知道您的要求,所以我无法推荐您应该做什么。示例选项是:
- 您的 zip/tar 应用程序和单独目录中的库。
- 创建包含所有相关代码的单个 jar。
- 解决方案 1 或 2,加上打包的 JRE。
- 带有您的代码和库的 运行time 图像,它也仅使用您需要的 JRE 和 JavaFX 模块的自定义 运行time 部分(使用 jlink)。
- 3 或 4 的本地安装程序(使用 jpackage + 本地安装程序创建工具,例如 WIX、RPM、DEB 安装程序创建者)。
最后一种方法(本机安装程序)是我为大多数重要应用程序推荐的打包、分发和安装方法。
你需要研究如何做到这一点
要获得您的解决方案,您需要进行自己的研究,并且,一旦您选择了一种方法和工具集,如果您仍然遇到困难,您可以创建一个关于该方法实施的新问题。
相关资源
- How can I create an executable JAR with dependencies using Maven?
- openjfx Runtime images documentation
- maven shade plugin
- openjfx JavaFX maven plugin
- badass runtime plugin
- badass jlink plugin
- jlink guide
- jpackage script
- JEP 392: packaging tool
阴影罐警告
如果使用 maven shade 插件将所有 JavaFX 代码捆绑到一个 jar 中,当您 运行 来自 Java 16 的应用程序时,您将收到如下警告+:
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @28c71909'
这表明不支持这样的配置,并且可能(并且可能会)在未来和当前的 JavaFX 平台修订版中中断。因此,我不推荐包含 JavaFX 平台代码的阴影 jar,即使此类 jar 当前可能适用于您的部署。
JavaFX 11+ 被构建为用作一组模块。如果配置不 运行 模块路径之外的 JavaFX 平台而是 运行 类路径之外的平台代码(就像阴影 jar 那样),则不支持这些配置。