如何在 Java 11 打包具有非模块化依赖项的应用程序

How to package app at Java 11 with non-modular dependencies

我开发并发布了一个 Java Swing 应用程序,它使用 Apache Batik 和 JavaCV。我已经通过 java 1.6、7 和 8 对其进行了更新。macOS、Windows 和 Linux 的安装程序是使用 Javapackager 构建的。 Java 8 将于 19 年 1 月结束支持,我无法在新的 LTS 版本 Java 11 找到打包和分发的解决方案。

JavaCV 或 Batik 均未生成模块化 jar,但我已设法将它们重新打包到可以在 Java 编译并生成可运行 jar 的程度 11,应用程序运行良好,但我可以' 打包分发。我计划下降到 Java 10 以使用 javapackager 并从那里捆绑 11 运行时,但它使用 jlink 生成自定义运行时,jlink 失败,因为 JavaCV 和 Batik 不是模块化的。由于 Batik 和 JavaCV 中的不满意引用,jdeps 不会生成模块-info.class 来修补并使它们模块化,即使我的应用程序在没有它们的情况下也能正常工作。

因此,我将不得不将代码库保留在 Java 8,并发布它,即使它不再受支持。

我知道有人呼吁创建 javapackager 的替代品,但要等到 Java 8 被弃用后才会出现。而且我仍然需要 Batik 和 JavaCV 项目来重构和构建模块化 jar 以生成自定义运行时。

有人可以提供任何其他解决方案吗?我错过了什么吗?谢谢

所以唯一的解决方案是编写一个使用 ProcessBuilder 启动原始应用程序 jar 的包装器应用程序。

这样做的好处是 link 可用于生成所需的最少运行时间。将 jar 放在 bin 目录中,然后使用 FPM (https://github.com/jordansissel/fpm) 创建安装程序。

包装器的示例代码

package xyz.arwhite.dslauncher;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class DrumScoreLauncher {

    public static void main(String[] args) {
        String installHome = System.getProperty("java.home");
        String installBin = installHome + File.separator + "bin" + File.separator;

        System.out.println("Launching Drum Score Editor from "+installHome);

        List<String> cmdLine = new ArrayList<String>();
        cmdLine.add(installBin + "java");
        cmdLine.add("-jar");
        cmdLine.add(installBin + "DrumScoreEditor.jar");

        for ( int i = 0; i < args.length; i++ )
            cmdLine.add(args[i]);

        try {
            ProcessBuilder p = new ProcessBuilder(cmdLine);
            p.inheritIO();
            p.start();

        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("Exiting launcher");
    }

}

更新:自 JDK 14 起现在包含 jpackage。不过,以下答案仍然适用于旧的 JDK 版本。


我遇到了同样的问题。我想使用 JDK 11,但根据 JDK-8212780 JEP 343 计划在 JDK 13,所以我们需要稍等一下更长。在 Java 8 - 10 下打包“本机”自包含应用程序不是问题,因为包含了打包程序(至少在 Oracle JDK 中)。

今天我发现了 this email and figured I'd like to give it a try: You can see my sample project on github.com/skymatic/javafx11-test,我使用 JDK 开发分支的向后移植 jpackager 成功打包了它。

我在这里做了什么:

  • 使用 OpenJDK 11 和 OpenJFX 11 创建了一个新的 HelloWorld 项目。
  • 下载打包器并从 Maven 构建调用它(注意它需要与 JDK 一起驻留并且您需要设置 JAVA_HOME 才能工作...)
  • 奖励:我使用 jdeps 找出非模块化 jar 的依赖项并设置 --add-modules 参数以生成较小的运行时图像

当然对于模块化项目更容易:在this commit to my sample project中你可以看到我使用jpackager的模块路径和主模块参数而不是class路径和主要 class.

这是一个 link 到 GitHub 的模板,展示了如何使用 jlink、jpackage 和 GitHub 操作来生成 JavaFX 应用程序和本机 macOS,Windows,和 Linux 个带有小型 JVM 的安装程序:

https://github.com/wiverson/maven-jpackage-template

这是一个使用 Swing 和嵌入式 Spring 引导服务器的 (WIP) 版本:

https://github.com/wiverson/desktop-spring-boot