Java 9第三方模块在IDE正常运行但jlink打包自定义JRE失败求助
嘿,这个问题我之前帮人排查过,核心原因是jlink对模块的要求比IDEA严格多了——IDEA能自动处理那些非模块化的第三方JAR(也就是自动模块),但jlink在JDK9里只认带module-info.java的显式模块,这就是你打包时出错的关键。咱们一步步来解决:
你用到的poi-3.17.jar、commons-io-2.6.jar、HikariCP-3.1.0.jar都是非模块化的JAR,在IDEA运行时,它们会被当作「自动模块」加载,但jlink不允许将自动模块包含到自定义JRE中,因为它需要明确的模块边界和依赖声明。
1. 先搞清楚第三方JAR的自动模块名
首先得知道这些JAR对应的模块名,用下面的命令逐个查看:
jar --file=poi-3.17.jar --describe-module jar --file=commons-io-2.6.jar --describe-module jar --file=HikariCP-3.1.0.jar --describe-module
举个例子,commons-io-2.6.jar的自动模块名通常是commons.io,HikariCP-3.1.0.jar大概率是com.zaxxer.hikari(如果JAR的MANIFEST里没指定,就是文件名去掉版本号,把连字符换成点)。
2. 把非模块化JAR转成显式模块
有两种靠谱的方式:
方式一:手动添加module-info.java
适合小范围的依赖转换:
- 先解压JAR文件:
unzip poi-3.17.jar -d poi-module - 在解压后的
poi-module根目录创建module-info.java,根据你的代码依赖编写声明,比如:module poi { // 导出你代码用到的POI包,比如操作Excel的核心包 exports org.apache.poi.ss.usermodel; // 声明依赖的其他模块 requires commons.io; requires java.desktop; // 如果用到反射调用POI内部类,还要用opens声明 // opens org.apache.poi.xssf.usermodel to your.module.name; } - 重新打包成模块化JAR:
对jar --create --file=poi-modular.jar -C poi-module .commons-io和HikariCP重复这个步骤。
方式二:用Moditect Maven插件自动生成
如果是Maven项目,这个插件能帮你自动给第三方JAR生成module-info.java并打包,省手动操作的麻烦。在pom.xml里加这段配置:
<plugin> <groupId>org.moditect</groupId> <artifactId>moditect-maven-plugin</artifactId> <version>1.0.0.Final</version> <executions> <execution> <id>add-module-info-to-deps</id> <phase>package</phase> <goals> <goal>add-module-info</goal> </goals> <configuration> <modules> <module> <artifact> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </artifact> <moduleInfo> <name>poi</name> <exports>org.apache.poi.ss.usermodel</exports> <requires>commons.io</requires> <requires>java.desktop</requires> </moduleInfo> </module> <!-- 给commons-io和HikariCP也加类似的配置 --> <module> <artifact> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </artifact> <moduleInfo> <name>commons.io</name> <exports>org.apache.commons.io</exports> </moduleInfo> </module> </modules> </configuration> </execution> </executions> </plugin>
执行mvn package后,插件会自动生成带module-info.java的模块化JAR。
3. 重新执行jlink命令
把转换后的模块化第三方JAR放到--module-path里,然后在--add-modules中加上这些模块名。比如:
jlink --module-path production:./modular-jars \ --add-modules studyModule,poi,commons.io,com.zaxxer.hikari,java.base,java.datatransfer,java.desktop,java.logging,java.scripting,java.sql,java.xml,java.prefs,javafx.base,javafx.controls \ --output custom-jre
这里的./modular-jars是你存放转换后模块化JAR的目录,确保所有依赖的模块都被包含进来。
额外小技巧
如果不确定要加哪些模块,可以用jdeps工具分析你的主模块依赖:
jdeps --module-path your-module-path --list-deps studyModule
它会列出所有直接和间接依赖的模块,照着加就行。
内容的提问来源于stack exchange,提问作者Mohd

