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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/53453212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:48:51  来源:igfitidea点击:

How to deploy a JavaFX 11 Desktop application with a JRE

javajavafxjavafx-11openjfx

提问by mcs75

I have a JavaFX (JDK 8) desktop business application, which uses Java Web Start for deployment. Users have Java 8 installed, and they simply go to the URL (a public URL on my AWS Linux server) and the application downloads / starts (using Web Start). I can easily update the application, too, by deploying new JARs to the server. Everything works well.

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

However, Oracle has discontinued Web Start with Java 11, and in their “Java Client Roadmap Update” white paper, March 2018, they recommend bundling a JRE with the application (“The notion of an application being distributed separately from a standalone JRE is, therefore, quickly fading.”). I cannot rely on my users to stay at Java 8 for Web Start, and even if they do remain at 8, Oracle requires a license to continue using Java 8 (which I do not have, can be very costly, and I'd prefer anyways to move with the community towards JavaFX 11 and OpenJDK).

但是,Oracle 已停止使用 Java 11 的 Web Start,并且在 2018 年 3 月的“Java 客户端路线图更新”白皮书中,他们建议将 JRE 与应用程序捆绑在一起(“应用程序与独立 JRE 分开分发的概念是,因此,很快就会消失。”)。我不能指望我的用户在 Web Start 上停留在 Java 8,即使他们仍然停留在 8,Oracle 需要一个许可证才能继续使用 Java 8(我没有,可能非常昂贵,我更喜欢无论如何要与社区一起向 JavaFX 11 和 OpenJDK 迈进)。

?I would like to migrate to JavaFX 11. I have followed OpenJFX's “Getting Started with JavaFX11” (https://openjfx.io/openjfx-docs/), using OpenJDK 11.0.1 with Gluon's JavaFX SDK 11.0.1 (on Netbeans 10vc2), and have been able to get the sample applications to run (and appears to me I should be able to port my JavaFX 8 code to JavaFX 11, quite easily).

?我想迁移到 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)。

However, this is where I am stuck for direction. How do I bundle this with the JRE and deploy this to my end-users (and provide application updates)? Is there an easy way out there (or even a hard way, with some direction/guides)?

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

I can spend hundreds of hours writing expressive, rich, and useful desktop business applications in JavaFX 11, but what do I do then?

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

Are the deployment toolkits, like JWrapper, InstallAnywhere, etc, suited to this new era of Java 11? Does Gluon/openjfx.io perhaps have a recommendation or guide I missed? I cannot seem to find any recommendations or guides from reputable sources, for how us developers, who focus on writing the front-end code, are to deploy the applications.

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

Thank you for any help or guidance.

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

回答by VGR

The way it works now is, you convert your program to a module, then “link” it to all the other modules it requires.

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

The result of this linking process is what's known as an image. An image is actually a file tree, which includes a bindirectory with one or more ready-to-run executables. This tree is what you distribute, typically as a zip or tar.gz.

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

The steps are:

步骤是:

  1. Create a module-info.java
  2. Compile with a module path instead of a classpath
  3. Create a jar from classes, as usual
  4. Convert jar to a jmod with the JDK's jmodtool
  5. Link that jmod, and the modules on which it depends, into an image
  1. 创建一个模块-info.java
  2. 使用模块路径而不是类路径进行编译
  3. 像往常一样从类创建一个 jar
  4. 使用 JDK 的jmod工具将 jar 转换为 jmod
  5. 将该 jmod 及其所依赖的模块链接到一个图像中

Writing a module descriptor

编写模块描述符

The first step is to turn the application into a module. Minimally, this requires creating a module-info.javaat the top of your source tree (that is, in the empty package). Every module has a name, which is often the same as a package name but doesn't have to be. So, your module-info.java might look like this:

第一步是将应用程序变成一个模块。至少,这需要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;
}

Building

建筑

When you build, you don't specify a classpath at all. Instead, you specify a module path.

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

A module path is a list of directories, not files. Each directory contains, not surprisingly, modules. The jmodsdirectory of the JDK is included implicitly. All you need to include is directories containing the non-JDK modules you need. In your case, that at least means Gluon's JavaFX:

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

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

Then you create a jar the usual way:

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

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

A jar file with a module-info.class in it is considered a modular jar.

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

Making a jmod

制作一个 jmod

Creating a jmod is usually a simple process:

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

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

Linking

链接

Finally, you use the JDK's jlinkcommand to assemble everything:

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

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

jlinkcreates a minimal JRE, which contains only the modules you explicitly add (and the modules those explicit modules require). --add-modulesis the required option that specifies what to add.

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

As with other JDK tools, --module-pathspecifies directories containing modules.

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

The --launcheroption causes the final image tree to have an additional executable script in its bindirectory with the given name (the part before the equals). So, MyBusinessApp=com.mcs75.businessappmeans “create an executable named MyBusinessApp, which executes the module com.mcs75.businessapp.”

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

Because the jmod createcommand included a --main-classoption, Java will know what to execute, just like declaring a Main-Class attribute in a manifest. It is also possible to explicitly declare a class to execute in the --launcheroption if desired.

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

Distributing

分发

What you will want to distribute is a zip or tar.gz of the entire image file tree. The executable that the user should run is in the image's bindirectory. Of course, you are free to add your own executables. You are also free to place this into any kind of installer, as long as the image tree's structure is preserved.

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

A future JDK will have a packaging toolfor creating full-fledged native installers.As of Java 14, the JDK has a jpackagetool which can create native installers. For example:

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

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

-nspecifies the name of the program. --runtime-imagespecifies the location of the existing jlink'd image. -mis the module and class within the jlink'd image to execute, much like the portion after the =in jlink's --launcheroption.

-n指定程序的名称。 --runtime-image指定现有 jlink 图像的位置。 -m是jlink'd图像内的模块和类来执行,很像后的该部分=在JLINK的--launcher选项。

Cross-building

交叉建设

Since the image includes native binaries, you will need to create an image for each platform. Obviously, one option is to build the image on a Linux system, and again on a Windows system, and again on a Mac, etc.

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

But you can also use jmodand jlinkto create images for other platforms, regardless of where you're building.

但您也可以使用jmodjlink为其他平台创建图像,无论您在何处构建。

There's only a few additional steps needed. First, you will need the JDKs for those other platforms. Download them as archives (zip or tar.gz), not installers, and unpack them to directories of your choice.

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

Each JDK defines a platformstring. This is normally of the form <os>-<arch>. The platform is a property of the java.basemodule; you can see any JDK's platform by examining that module:

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

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

Pass that platform string to your jmod command using the --target-platformoption:

使用以下--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

Finally, when linking, you want to explicitly include the other JDK's jmodsdirectory, so jlink won't implicitly include its own JDK's modules:

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

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

回答by David Miller

To make things easier use an IDE, I use Intellij Idea; build automation, I use gradle; and jlink plugin, I use the badass Jlink plugin - https://badass-jlink-plugin.beryx.org/releases/latest/#jpackageImage. You can then easily use jlink and jpackage. Just a thought.

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