前情提要:使用java模块化写了一个javafx应用,和非模块化打包不一样。
java版本:java17
javafx-version: 21.0.1
1. Java模块化打包配置
试图打包,出现报错:找不到模块javafx.control
仔细一看,module-info.java里所有模块都找不到
解决:maven-compiler-plugin版本太低,要高于哪个版本才能,具体哪个版本忘了,3.8.1可行。
继续点击package,报错:找不到符号
大片的找不到符号,观察一下是Lombok注解的Getter等部分找不到符号。那么是Lombok配置不对。
搜索一下发现要下Lombok插件,但这个插件在2022版本IDEA里搜索不到。于是去官网下载:Lombok
但官网下完还要改一改版本。打开IDEA的about,找到版本号:Build #IU-223.8214.52, built on December 20, 2022,也就是223.8214.52。
然后进入下载好的zip,用winRAR,或者别的什么解压软件打开lombok-plugin-0.34-2020.2.jar,进入META-INF,打开plugin.xml,如下:
在倒数第二行的since-build那里改成对应的版本号,后面的until-build没找到,填大一点就可以,然后安装到IDEA里。
装完了发现还是找不到符号,最后发现要在maven-compiler-plugin里加几行配置(完整xml见末尾):
<annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </path> </annotationProcessorPaths>
然后可以顺利打包。Lombok插件需不需要不确定。
2. jlink
接下来觉得jre太大,想要用jlink链接一个包出来。这也是模块化后可以用的功能。虽然最后打出来的包有150M比直接导出70M的jre还大完全没有用,但还是记一下。
加一个javafx-maven-plugin的插件,然后点击jlink:
报错:Error: Error reading module: xxxxx/xxx/target
点进源码里试图来一些高深的debug,未果。搜到一个相关的issue:jlink fails reading module #113
意思是如果没指定jlink运行路径,它会自己找到java home然后运行jlink。当前环境变量里的java版本是java8,但这个项目是java17,所以报错了。然而在环境变量里改过来还是不行,最后需要加一个javafx-maven-plugin的配置:
<jlinkExecutable>D:\Java\java17\bin\jlink</jlinkExecutable>
就是在java bin目录下找到jlink填进去
然后遇到新的报错,甚至是乱码:����: pdfbox路径
��
很崩溃,刚好收到未来上班公司邮件,先签个卖身契缓解一下情绪(?
之前搜资料的时候有看到不是所有包都模块化,也就是有module-info的。显然pdfbox就没有module-info。为了jlink我们得给它注入一个:jar的module-info模块信息注入
这篇博客很完善了,特别注意存一下原来的jar。
然后对log4j也注入一下,jlink完成。从jdk里生成jre倒也是用的同样方法:
bin\jlink.exe --module-path jmods --add-modules java.desktop --output jre
3. 打包为exe
现在我们有jar包,有jre,放到exe4j里合一下,发现还缺了点依赖。接下来加一个插件maven-shade-plugin。理论上maven-assembly-plugin也可以,但我们用到了ikonli,一个javafx的icon包,用assembly打包会缺资源,详见:Error using the Ikonli font library java.lang.UnsupportedOperationException #11
现在有了带依赖的jar包,可以和jre放一起,合成能在没有java环境里跑的应用程序。
4. 另外的打包方式
Gradle
gradle的javafx打包插件更新更及时一点,但没试。
Graalvm
使用 GraalVM 将纯 JavaFX 项目打包成 EXE
简而言之要下一个VS2022提供环境,这位更是重量级。
完整但jlink配置完全多余的pom.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.example</groupId> <artifactId>PdfPaperTool</artifactId> <version>1.0</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <javafx-version>21.0.1</javafx-version> <lombok.version>1.18.20</lombok.version> </properties> <dependencies> <!--javafx icon--> <dependency> <groupId>org.kordamp.ikonli</groupId> <artifactId>ikonli-fontawesome-pack</artifactId> <version>12.3.1</version> </dependency> <dependency> <groupId>org.kordamp.ikonli</groupId> <artifactId>ikonli-javafx</artifactId> <version>12.3.1</version> </dependency> <!--Explanation of JavaFX modules: https://openjfx.io/javadoc/17/--> <!--javafx.base and javafx.graphics are automatically pulled when javafx.control imported--> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>${javafx-version}</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-fxml</artifactId> <version>${javafx-version}</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-swing</artifactId> <version>${javafx-version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.24</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>17</source> <target>17</target> <encoding>UTF-8</encoding> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.2</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.pdfTool.AppRun</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.openjfx</groupId> <artifactId>javafx-maven-plugin</artifactId> <version>0.0.8</version> <executions> <execution> <id>default-cli</id> <configuration> <source>17</source> <target>17</target> <mainClass>com.pdfTool/com.pdfTool.AppRun</mainClass> <launcher>app</launcher> <jlinkZipName>app</jlinkZipName> <jlinkImageName>app</jlinkImageName> <noManPages>true</noManPages> <stripDebug>true</stripDebug> <noHeaderFiles>true</noHeaderFiles> <jlinkExecutable>D:\Java\java17\bin\jlink</jlinkExecutable> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>