39

我有一个 JavaFX (JDK 8) 桌面业务应用程序,它使用 Java Web Start 进行部署。用户安装了 Java 8,他们只需访问 URL(我的 AWS Linux 服务器上的公共 URL)并下载/启动应用程序(使用 Web Start)。通过将新的 JAR 部署到服务器,我也可以轻松地更新应用程序。一切正常。

但是,Oracle 已停止使用 Java 11 进行 Web Start,并且在 2018 年 3 月的“Java 客户端路线图更新”白皮书中,他们建议将 JRE 与应用程序捆绑在一起(“应用程序与独立 JRE 分开分发的概念是,因此,迅速褪色。”)。我不能指望我的用户继续使用 Java 8 进行 Web Start,即使他们确实保持在 8,Oracle 也需要许可证才能继续使用 Java 8(我没有,可能非常昂贵,我更喜欢无论如何都要与社区一起转向 JavaFX 11 和 OpenJDK)。


我想迁移到 JavaFX 11。我遵循 OpenJFX 的“JavaFX11 入门”(https://openjfx.io/openjfx-docs/),使用 OpenJDK 11.0.1 和 Gluon 的 JavaFX SDK 11.0.1(在 Netbeans 10vc2 上) ),并且已经能够运行示例应用程序(在我看来,我应该能够很容易地将我的 JavaFX 8 代码移植到 JavaFX 11)。

然而,这是我被困住的方向。如何将其与 JRE 捆绑并将其部署给我的最终用户(并提供应用程序更新)?有没有简单的方法(甚至是困难的方法,有一些方向/指南)?

我可以花费数百小时在 JavaFX 11 中编写富有表现力、丰富且有用的桌面业务应用程序,但我该怎么办?

JWrapper、InstallAnywhere 等部署工具包是否适合 Java 11 的新时代?Gluon/openjfx.io 是否有我错过的推荐或指南?对于我们专注于编写前端代码的开发人员如何部署应用程序,我似乎无法从知名来源找到任何建议或指南。

感谢您的任何帮助或指导。

4

3 回答 3

40

它现在的工作方式是将程序转换为模块,然后将其“链接”到它需要的所有其他模块。

这个链接过程的结果就是所谓的图像。映像实际上是一棵文件树,其中包括一个bin目录,其中包含一个或多个可立即运行的可执行文件。这棵树就是您分发的内容,通常以 zip 或 tar.gz 的形式分发。

步骤是:

  1. 创建一个 module-info.java
  2. 使用模块路径而不是类路径编译
  3. 像往常一样从类创建一个 jar
  4. jmod使用 JDK 的工具将 jar 转换为 jmod
  5. 将该 jmod 及其所依赖的模块链接到图像中

编写模块描述符

第一步是将应用程序变成一个模块。最低限度,这需要module-info.java在源代码树的顶部(即在空包中)创建一个。每个模块都有一个名称,通常与包名称相同,但并非必须如此。因此,您的 module-info.java 可能如下所示:

module com.mcs75.businessapp {
    exports com.mcs75.desktop.businessapp;

    requires java.logging;
    requires transitive javafx.graphics;
    requires transitive javafx.controls;
}

建造

构建时,您根本不指定类路径。相反,您指定一个模块路径。

模块路径是目录列表,而不是文件。毫不奇怪,每个目录都包含模块。JDK的jmods目录是隐含的。您需要包含的只是包含您需要的非 JDK 模块的目录。在您的情况下,这至少意味着 Gluon 的 JavaFX:

javac -Xlint -g -d build/classes --module-path /opt/gluon-javafx/lib \
    src/java/com/mcs75/desktop/businessapp/*.java

然后以通常的方式创建一个 jar:

jar -c -f build/mybusinessapp.jar -C build/classes .

包含 module-info.class 的 jar 文件被视为模块化 jar。

制作一个jmod

创建 jmod 通常是一个简单的过程:

mkdir build/modules
jmod create --class-path build/mybusinessapp.jar \
    --main-class com.mcs75.desktop.businessapp.BusinessApplication \
    build/modules/mybusinessapp.jmod

链接

最后,您使用 JDK 的jlink命令来组装所有内容:

jlink --output build/image \
    --module-path build/modules:/opt/gluon-javafx/lib \
    --add-modules com.mcs75.businessapp \
    --launcher MyBusinessApp=com.mcs75.businessapp

jlink创建一个最小的 JRE,其中仅包含您显式添加的模块(以及那些显式模块需要的模块)。 --add-modules是指定要添加的内容的必需选项。

与其他 JDK 工具一样,--module-path指定包含模块的目录。

该选项会导致最终图像树在其目录中具有给定名称(等号之前的部分)--launcher的附加可执行脚本。bin所以,MyBusinessApp=com.mcs75.businessapp意思是“创建一个名为 MyBusinessApp 的可执行文件,它执行模块 com.mcs75.businessapp。”</p>

因为该jmod create命令包含一个--main-class选项,Java 将知道要执行什么,就像在清单中声明 Main-Class 属性一样。如果需要,也可以在--launcher选项中显式声明要执行的类。

分发

您将要分发的是整个图像文件树的 zip 或 tar.gz。用户应该运行的可执行文件位于图像的bin目录中。当然,您可以自由添加自己的可执行文件。只要保留图像树的结构,您也可以自由地将其放入任何类型的安装程序中。

未来的 JDK 将有一个用于创建成熟的本地安装程序的打包工具。 从 Java 14 开始,JDK 有一个jpackage工具,可以创建本机安装程序。例如:

jpackage -n MyBusinessApp --runtime-image build/image \
    -m com.mcs75.businessapp/com.mcs75.desktop.businessapp.BusinessApplication

-n指定程序的名称。 --runtime-image指定现有 jlink'd 图像的位置。 -m是 jlink'd 映像中要执行的模块和类,很像 in jlink 选项之后的=部分--launcher

交叉建设

由于映像包含本机二进制文件,因此您需要为每个平台创建一个映像。显然,一种选择是在 Linux 系统上构建映像,然后在 Windows 系统上构建映像,然后在 Mac 上构建,等等。

但是,无论您在哪里构建,您也可以使用jmod和创建其他平台的图像。jlink

只需要几个额外的步骤。首先,您将需要其他平台的 JDK。将它们下载为档案(zip 或 tar.gz),而不是安装程序,然后将它们解压到您选择的目录中。

每个 JDK 都定义了一个平台字符串。这通常是 <os>-<arch> 的形式。平台是java.base模块的属性;通过检查该模块,您可以看到任何 JDK 的平台:

jmod describe path-to-foreign-jdk/jmods/java.base.jmod | grep '^platform'

使用以下选项将该平台字符串传递给您的 jmod 命令--target-platform

mkdir build/modules
jmod create --target-platform windows-amd64 \
    --class-path build/mybusinessapp.jar \
    --main-class com.mcs75.desktop.businessapp.BusinessApplication \
    build/modules/mybusinessapp.jmod

最后,在链接时,您希望显式包含其他 JDK 的jmods目录,因此 jlink 不会隐式包含自己的 JDK 模块:

jlink --output build/image \
    --module-path path-to-foreign-jdk/jmods:build/modules:/opt/gluon-javafx-windows/lib \
    --add-modules com.mcs75.businessapp \
    --launcher MyBusinessApp=com.mcs75.businessapp
于 2018-11-23T22:29:58.367 回答
1

为了让事情更容易使用 IDE,我使用 Intellij Idea;构建自动化,我使用 gradle;和 jlink 插件,我使用 badass Jlink 插件 - https://badass-jlink-plugin.beryx.org/releases/latest/#jpackageImage。然后您可以轻松地使用 jlink 和 jpackage。只是一个想法。

于 2020-03-28T15:34:51.650 回答
0

虽然其他答案有很多关于如何手动执行此操作的详细信息,但也可以使用构建工具插件,例如 Maven。

例如,使用JavaPackager Maven 插件,只需在 POM 中添加类似这样的内容就足够了:

<plugin>
    <groupId>io.github.fvarrui</groupId>
    <artifactId>javapackager</artifactId>
    <version>1.6.2</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>package</goal>
            </goals>
            <configuration>
                <mainClass>...</mainClass>
                <bundleJre>true</bundleJre>
                <platform>windows</platform>
            </configuration>
        </execution>
    </executions>
</plugin>

运行mvn package将在“target”内生成一个包含 EXE 的目录、一个“jre”目录和一个“libs”目录。该插件还可以生成安装程序文件。

显然,对于不同的平台,您需要调整配置,但我在 Windows 上使用 JDK 16 和 17 进行了测试,它似乎工作正常。

于 2021-11-22T17:22:25.133 回答