如何在jlink中使用签名模块化JAR并规避JCE Provider运行报错?
解决jlink构建含签名JCE Provider(如BouncyCastle)的运行时镜像问题
咱们先把问题拆解清楚:你用jlink打包时遇到的是签名模块化JAR不被jlink支持,以及后续运行时JCE Provider签名验证失败的双重矛盾——BouncyCastle作为第三方JCE Provider,必须签名才能被JVM信任,但jlink没法直接处理签名的模块化JAR,强行用--ignore-signing-information跳过检查后,运行时又会因为签名验证失败抛出异常。
下面给你几个可行的解决办法,按实用程度排序:
方案1:将BouncyCastle作为外部依赖加载(最稳妥)
既然jlink搞不定签名JAR,那咱们就不把它打包进镜像,让运行时从外部加载:
- 调整jlink命令,不要把bcprov.jdk15on.jar加入
--module-path,也不要在--add-modules里包含它的模块 - 把bcprov.jdk15on.jar放到应用目录下的单独文件夹,比如
./lib/ - 运行生成的可执行文件时,通过参数指定这个外部JAR:
这种方式彻底避开了jlink和签名JAR的冲突,JVM也能正常验证BouncyCastle的签名,不会出现认证异常。# 模块化方式加载 ./dist/bin/launch --module-path ./lib/bcprov.jdk15on.jar --add-modules org.bouncycastle # 或者类路径方式(如果你的应用不是模块化的) ./dist/bin/launch -cp ./lib/bcprov.jdk15on.jar
方案2:用jpackage配合打包(适合生成安装包)
如果你需要生成单文件或系统安装包,可以结合jpackage和jlink来处理:
- 先构建不含BouncyCastle的jlink镜像(也就是去掉模块路径里的bcprov.jdk15on.jar)
- 用jpackage打包时,通过
--input参数指定存放bcprov.jdk15on.jar的目录,jpackage会自动把它放到应用的lib目录并配置好加载路径:
这样生成的安装包会自动处理外部依赖,运行时能正确加载并验证BouncyCastle。jpackage --name MyDemoApp --module org.demo/org.demo.Main --runtime-image dist --input ./lib
方案3:修改BouncyCastle JAR为非签名模块化JAR(不推荐,有安全风险)
如果你一定要把BouncyCastle打包进镜像,可以尝试移除它的签名并重新模块化:
- 解压bcprov.jdk15on.jar,删除
META-INF目录下的所有签名相关文件(比如.SF、.DSA、.RSA后缀的文件) - 添加
module-info.java文件(如果原JAR没有模块化描述的话),示例内容如下:module org.bouncycastle { exports org.bouncycastle.jce.provider; provides java.security.Provider with org.bouncycastle.jce.provider.BouncyCastleProvider; requires java.base; requires java.security.jgss; // 根据你的实际使用情况添加其他依赖模块 } - 重新编译并打包成模块化JAR:
# 编译module-info.java javac --module-path . -d tmp module-info.java # 重新打包JAR jar --create --file bcprov-mod.jar -C tmp . -C ./original-bc-unpacked . - 用这个修改后的非签名JAR执行jlink命令,不需要加
--ignore-signing-information,运行时也不会抛出异常。注意:这种方式会失去JCE Provider的签名验证机制,存在安全隐患,不建议在生产环境使用。
问题根源补充
- jlink的
--ignore-signing-information只是在打包阶段跳过了签名检查,但JVM运行时依然会严格验证JCE Provider的签名。而jlink在打包过程中会重新处理模块内容,导致原JAR的签名信息被破坏,所以运行时会抛出Non-Oracle JCE providers may not be linked into the image异常。 - Oracle JVM对JCE Provider有强制签名要求,第三方Provider必须经过签名才能被加载,但目前jlink还不支持保留签名模块化JAR的完整性。
内容的提问来源于stack exchange,提问作者pinpinokio
相关产品推荐
相关产品推荐

