这是一个使用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逻辑,我们试图构建应用程序的方法是将pom1.xml指令的结果maven到package
我们得到了上面提到的错误:
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,它不包括所有依赖库代码(这就是为什么当您试图运行应用程序时无法找到依赖代码)。
您可以使用程序集打包应用程序代码和依赖库,如如何使用Maven创建具有依赖关系的可执行JAR中详细介绍的那样?,尽管这种方法并不是解决你问题的唯一方法。
您需要构建某种运行时映像
构建运行时映像有很多选项,我不知道你的需求,所以我不能推荐你应该做什么。示例选项有:
- 一个单独目录下的应用程序和库的zip/tar文件。
- 创建一个包含所有依赖代码的jar。
- 方案1或方案2中的任意一种,加上包含打包的JRE。
- 包含代码和库的运行时映像,它还使用您需要的JRE和JavaFX模块的自定义运行时部分(使用jlink)。
- 3或4的本机安装程序(使用jpackage +本机安装程序创建工具,例如WIX, RPM, DEB安装程序创建器)。
最后一种方法(本机安装程序),是我为大多数重要应用程序推荐的打包、分发和安装方法。
你需要研究如何做到这一点
为了得到你的解决方案,你需要做你自己的研究,一旦你选择了一种方法和工具集,如果你仍然有困难,你可以创建一个关于该方法实施的新问题。
相关资源
- 如何使用Maven创建具有依赖关系的可执行JAR ?
- openjfx Runtime images documentation
- maven shade插件
- Maven Shade JavaFX运行时组件丢失
- openjfx JavaFX maven plugin <
- jlink指南/gh><
- jpackage脚本/gh>JEP 392:包装工具
有阴影的罐子警告
如果您使用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所做的那样),则不支持配置。