使用Maven Shade插件打包含JavaFX依赖的Jar后运行提示“JavaFX runtime components are missing”问题排查
Hey,我来帮你排查这个问题!你遇到的「JavaFX runtime components are missing」报错其实是JavaFX模块化特性带来的常见坑,结合你的pom配置和操作步骤,主要有这几个关键点需要调整:
1. 先统一所有JavaFX依赖的版本
看你的pom里,JavaFX各组件的版本完全混乱了:javafx-controls用的是11,javafx-media是20-ea+9,javafx-fxml又是17.0.2,甚至javafx-graphics的三个平台分类器版本也没和其他组件对齐。版本不一致会导致依赖不兼容,运行时自然找不到完整的JavaFX runtime组件。
建议把所有JavaFX依赖的版本统一成同一个稳定版,比如17.0.2(LTS版本,兼容性更好),可以用Maven属性来统一管理,避免手动改错:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <junit.version>5.8.2</junit.version> <javafx.version>17.0.2</javafx.version> <!-- 新增统一版本属性 --> </properties>
然后把所有JavaFX依赖的<version>都改成${javafx.version},包括javafx-graphics的三个平台依赖,确保版本完全一致。
2. 给Maven Shade插件添加必要的资源转换器
JavaFX有很多特殊资源(比如平台原生库、FXML文件、国际化资源、服务配置),默认的Shade插件配置没处理这些,导致打包后这些资源无法被JVM正确识别。你需要在Shade插件的<transformers>里添加几个关键转换器:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <!-- 建议用最新稳定版 --> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <!-- 配置主类 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.example.softwarertf.MenuExample</mainClass> </transformer> <!-- 处理JavaFX国际化资源 --> <transformer implementation="org.apache.maven.plugins.shade.resource.Native2AsciiResourceTransformer"/> <!-- 合并服务加载配置文件 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <!-- 合并模块描述符(适配JavaFX模块化特性) --> <transformer implementation="org.apache.maven.plugins.shade.resource.ModuleInfoResourceTransformer"/> </transformers> <!-- 排除签名文件,避免打包后签名冲突 --> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin>
3. 尝试用非Application类作为启动入口(可选但有效)
如果你的MenuExample是直接继承javafx.application.Application的,直接用java -jar运行时,JVM会强制以模块化方式加载应用,但Shade打包后的Jar可能没有完整的模块结构,容易触发报错。
可以新增一个普通的启动类,在里面间接启动JavaFX应用:
package com.example.softwarertf; public class MainLauncher { public static void main(String[] args) { // 调用JavaFX应用的main方法 MenuExample.main(args); // 或者用Application.launch方法 // javafx.application.Application.launch(MenuExample.class, args); } }
然后把Shade插件配置里的<mainClass>改成com.example.softwarertf.MainLauncher,这样JVM会以普通Java应用的方式启动,绕开模块化检查,很多时候能解决这个报错。
4. 验证打包后的Jar内容
重新执行mvn clean package后,用以下命令查看Jar里的内容,确认JavaFX的类和原生库都被正确打包:
jar tf SoftwareRtf-1.0-SNAPSHOT.jar
你应该能看到javafx开头的包路径,以及META-INF/native目录下对应你平台的原生库文件(比如Mac的.dylib、Windows的.dll、Linux的.so)。
按照这几步调整后,再用java -jar SoftwareRtf-1.0-SNAPSHOT.jar运行,应该就能正常启动了!
备注:内容来源于stack exchange,提问作者Gionata Donati

