在过去的 15 年左右的时间里,我工作的组织一直使用 Java 网络启动协议 (JNLP) 在内部向其用户分发 Java Swing 桌面应用程序。
要访问 Java Swing 应用程序,用户必须安装特定版本的 Java 平台标准版 (Java SE),其中包含对 JNLP 的支持。 当他们想要使用该应用程序时,他们会单击该组织内部网中的链接,Java Web Start (javaws) 程序将下载链接中的 XML,对其进行解释,并在必要时下载该应用程序的当前版本并运行它,同时管理应用程序运行的安全沙箱。 换句话说,这是一种将完全配置的应用程序分发到每个人桌面上的简单、低仪式的方法。
但是,由于 JNLP 不再是 Java SE 的一部分 (从版本 11 开始),该组织面临一个决定:停止使用作为 Java SE 一部分的 JNLP,或者放弃保持 Java SE 版本合理更新的策略。 由于各种原因,这个听起来相对简单的选择变得有些复杂。
选项 1:继续使用当前的 Java SE 并找到 JNLP 的替代品
IcedTea-Web 是一个提供 JNLP 功能的开源项目。 这意味着需要一个两步预配置过程:1) 安装 Java SE 和 2) 安装 IcedTea-Web,这将增加客户端维护。 不幸的是,当我们评估这些选项时,没有与 Java 11 兼容的 IcedTea-Web 设施,因此这意味着使用 Java 8。 但是,Java SE 8 将在 2019 年 3 月达到生命周期结束,因此我们将不得不从 OpenJDK 8 创建 Java 8 运行时环境,以便在客户端机器上安装,并转向更手动的过程来跟踪 OpenJDK 8 的更新。 这两种方法似乎都不太有吸引力。
选项 2:放弃使用 JNLP
起初,这种方法似乎是最糟糕的情况——我们需要修改应用程序以某种其他方式提供配置信息; JNLP 中所有漂亮的自动更新的东西都将被丢弃; 我们需要某种工作站安装过程。 哎呀! 或者我们可以将用户社区喜欢的现有胖客户端应用程序重写为 Web 应用程序。 双重哎呀!!!
所有这些负面情绪都被一些有趣的发现和一点仔细的思考所克服
- 配置信息可以作为元数据打包在元数据表中,最终用户可以选择该表作为“配置”。
- 应用程序可以相当容易地根据当前分发的版本号检查其版本号,并拒绝运行,或者至少向任何运行过时版本的用户发出抱怨。
- 可以将应用程序与自定义的 Java 运行时环境打包在一起,该运行时环境 使用 Open JDK 11 中提供的 jdeps 和 jlink 命令创建,从而确保应用程序始终使用正确的 Java 版本运行。
- 整个安装和执行业务可以在客户端使用 Windows .cmd 文件处理,从而无需安装程序(也许有一天……)。
- 应用程序和自定义的 Java 运行时分发仍然可以作为从内部网的下载来处理。
有了这个细节,细心的读者也许能够猜到……
选择的解决方案
最终,该组织决定放弃使用 JNLP,因为与维护现有的 JNLP 环境相比,最终用户管理的数量似乎相当简单。
以下是获得解决方案的详细过程
- 构建应用程序
- 该应用程序始终使用在 Linux 桌面环境中运行的 NetBeans IDE 开发和维护; 现在仍然如此,使用 OpenJDK 11(来自发行版)和 NetBeans 10(从 新的 Apache NetBeans 站点下载)。
- 构建过程创建一个与操作系统无关的 dist 文件夹,其中包含应用程序 .jar 文件和所有必需的库
- 自定义 Java 11 运行时
- 不幸的是,没有办法自定义跨平台的 Java 运行时,所以我们需要一台中间 Windows 计算机——我们称之为 IWC。 (我将直接说这是我们方法的主要缺点。)
- OpenJDK 11 预构建二进制文件安装在 IWC 上。
- 应用程序 dist 文件夹被复制到 IWC。
- 在 dist 文件夹中,来自 OpenJDK 11 的 jdeps 命令确定支持应用程序所需的 Java 运行时组件
jdeps --print-module-deps TheApplication.jar lib\*
- 使用上述命令的输出,jlink 命令(也来自 OpenJDK 11)构建自定义运行时
jlink --no-header-files --no-man-pages --compress=2 \ --strip-debug –add-modules \ java.base,java.desktop,java.sql,java.security.jgss,java.xml \ --output customjre
- 此时,可以使用以下命令从此文件夹运行(测试)应用程序
.\customjre\bin\java -jar TheApplication.jar
- Install.cmd 和 RunTheApplication.cmd 文件被复制到 dist 文件夹中。
- 打包应用程序以进行分发
- 包含应用程序、.cmd 文件和自定义运行时的 dist 文件夹被压缩并放在内部网服务器上; 指向 .zip 文件的链接允许用户下载它。
- 下载、安装和运行应用程序
- 用户导航到包含指向 .zip 文件的链接的页面。
- 单击该链接下载 .zip 文件。
- 用户解压缩 .zip 文件,导航到 dist 文件夹,然后双击 Install.cmd。
- 当 Install.cmd 执行时,它会将 dist 文件夹复制到用户计算机上的已知位置,并在用户的桌面上安装 RunTheApplication.cmd 链接。
- 用户需要具有某些权限才能安装该应用程序。
- 用户不需要在计算机上安装 Java SE。
应用程序已修改为
- 从数据库表中读取配置参数(该组织将这些参数视为“项目参数”,因此用户正在“选择一个项目”)。
- 从本地和服务器上的 RELEASE_NOTES.TXT 中提取 VERSION=123 字符串,以确保版本匹配(如果版本不匹配,最终用户会受到骚扰)。
就是这样。 当然,可以使用安装程序而不是 .cmd 文件来获得“更专业”的安装体验。 还可以找到其他方法在 IWC 上安装 OpenJDK 11,它甚至可以是一个虚拟机(使其成为 VIWC)。 可惜的是 jlink 命令没有 --target-platform 选项或许多其他改进,这些改进可能是根据部署环境的性质所希望的或必要的。
效果如何?
早期报告表明用户对结果感到满意,系统管理员不再负责监控已安装的 Java SE 版本。 至于支持该应用程序的人,他对额外的构建步骤或多或少没问题——但宁愿处理两台机器,也不愿在他的漂亮的 System76 笔记本电脑上运行 VIWC。
4 条评论