如何使用JRE部署JavaFX 11桌面应用程序

45

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

然而,Oracle已经在Java 11中停止了Web Start,并且在他们的“Java Client Roadmap Update”白皮书中(2018年3月)建议将JRE与应用程序捆绑在一起(“因此,从独立的JRE中分发应用程序的概念正在迅速消失”)。我不能指望我的用户保持Java 8使用Web Start,即使他们仍然使用8,Oracle也要求需要许可证才能继续使用Java 8(这是我没有的,可能非常昂贵,而且我更倾向于跟随社区发展,向JavaFX 11和OpenJDK迁移)。

我想迁移到JavaFX 11。我遵循了OpenJFX的“Getting Started with 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是否有我错过的建议或指南?我似乎找不到任何来自可靠来源的关于我们这些专注于编写前端代码的开发人员如何部署应用程序的建议或指南。

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


3
应用程序的部署视图文档非常少,而且在使用Java11+构建和部署应用程序方面发生了重大变化。你可以尝试使用jlink创建运行时映像。但对于社区来说,你需要一步步进行发布并提供解决方案。 - Naman
使用 JDK 中附带的 jlink 工具,您可以创建一个自包含、定制化的 JRE,其中仅包含应用程序需要的部分。我认为这就是 Oracle 现在认为你应该使用的,而不是 Web Start。 - Jesper
截至2018年12月1日,有一篇更详细的帖子提供了更多信息:medium.com/@adam_carroll/java-packager-with-jdk11-31b3d620f4a8 - mcs75
2
只是好奇采用这种新方法后可执行文件的大小会有多大? - Magnus
2
在JavaFX被从Oracle分离出来并转交给Gluon之后,可以在JavaFX的新主页上找到这些教程 - Basil Bourque
@BasilBourque 谢谢!!!这对我真的有用,我一直在遇到无法运行可执行JAR文件的问题,而这解决了它。 - hfontanez
3个回答

44
现在的工作方式是,将程序转换为模块,然后“链接”它到所有其他所需的模块。
这个链接过程的结果被称为一个镜像。镜像实际上是一个文件树,其中包括一个带有一个或多个可运行可执行文件的bin目录。这个树是你通常会分发的,比如zip或tar.gz。
步骤如下:
1. 创建一个module-info.java 2. 使用模块路径而不是类路径进行编译 3. 像往常一样从类创建jar 4. 使用JDK的jmod工具将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。”

由于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映像中要执行的模块和类,类似于jlink的--launcher选项中=后面的部分。

交叉构建

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

但是,您还可以使用jmodjlink为其他平台创建映像,而不管您正在构建的位置。

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

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

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

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

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

3
截至2018年12月1日,此事有更多信息发布在以下链接中:https://medium.com/@adam_carroll/java-packager-with-jdk11-31b3d620f4a8 - mcs75
2
你如何最好地在Maven中集成这些步骤? - IggyBlob
1
@IggyBlob 我不使用Maven,所以我不知道。不过,就我所知,我搜索了“maven goal jlink”,找到了https://maven.apache.org/plugins/maven-jlink-plugin/usage.html。 - VGR
在构建另一个平台时使用 jlink,是否需要指向该平台的 javafx jmods? - Icedude_907
1
@Icedude_907 是的。 - VGR
显示剩余2条评论

1

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进行了测试,似乎工作正常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接