如何将动态JVM命令行标志传递给独立的JavaFX应用程序?

ctr*_*den 5 java deployment jvm javafx

编辑:Oracle接受我的错误报告,请求增强功能作为JDK-8138944:支持将JVM的命令行参数传递给自包含的应用启动器

问题

我的团队正在开发一个开源Java SE项目ImageJ,该项目目前具有使用跨平台C编写的自定义本机启动器。我们希望脱离该启动器,转而使用更现代的行业标准和可维护的部署机制。 。迄今为止,JavaFX自包含应用程序是最有前途的解决方案。

ImageJ当前本机启动器的一大功能是能够自定义JVM启动方式的功能。例如,您可以编写:

ImageJ --debugger=8000 myFile.png
Run Code Online (Sandbox Code Playgroud)

启动器将使用以下标志调用JVM:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=localhost:8000
Run Code Online (Sandbox Code Playgroud)

同时将myFile.png用作Java主类的参数。

但是从文档中,我们看不到使用JavaFX打包工具完成类似操作的方法。

注意事项

我知道UserJvmOptionsService提供了一种配置JVM(如何通过内部的Java Preferences API来启动JVM)的方法,JavaFX启动器会在JVM启动之前读取它。这非常适合为用户提供一个友好的对话框,用户可以在其中调整最大堆大小和其他常用参数。当然,我们可以在这样的对话框中添加远程调试开关和端口设置,和/或通过CLI支持JVM配置,但是这将需要重新启动应用程序。

理想情况下,我们完全不需要支持这种情况,而是在Java启动JVM之后处理所有命令行参数。例如,在大多数情况下,-Dfoo=bar只要在应用程序的启动周期中尽早完成操作,就可以通过简单地解析arg并在运行时设置系统属性来支持表单的系统属性。但是很明显,在许多情况下,JVM启动后为时已晚:

我们的用户希望能够在CLI上传递这些设置,并相应地运行Java运行时-对于ImageJ,这对于向后兼容特别重要。

可能的解决方案

  • 我们可以保留本机C启动器,代替Java打包工具安装的本机可执行文件。但这使我感到非常脆弱,并且在很大程度上违反了切换到JavaFX部署的目的,因为我们仍然需要在多个不同平台上维护,构建和测试自定义本机启动器。

  • 或者,我们可以让应用程序主类是一个非常瘦的CLI选项解析器,然后生成第二个JVM实例。这将使引导程序逻辑保持在纯Java中,它比当前的本机C代码更具可维护性,同时充分利用JavaFX部署方案的跨平台捆绑功能。但这似乎是一个巨大的突破,具有潜在的挑战性副作用。

最后,问题

有人通过JavaFX自包含应用程序部署实现了对JVM CLI参数的支持吗?如果是这样,您是如何做到的?如果没有,还有其他建议吗?

小智 0

我建议您通过复制和编辑平台 java.c 启动器来创建自己的本机启动器,而不是使用任何类型的两阶段启动系统(在该系统中您可以看到有哪些选项,然后启动替代 JVM)。你可以在开放的JDK项目中看到他们在做什么。

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/914cd9b482c8/src/share/bin/java.c

他们在很多地方寻找各种选项并将它们转换为 JVM 本身的初始化参数。看一下 ParseArguments、AddApplicationOptions、TranslateApplicationArgs、CheckJvmType、AddOption 等函数。

我不是 C 程序员,但我在很多情况下维护过自己的启动器:例如从每行一个条目的文本文件加载特定类路径的启动器,该文件可以签入源代码管理,并且使用main() 的不同入口点。它的变化不大,您可以很容易地隔离您的更改,以便可以轻松地在更高版本的 java.c 上重新应用它们。出于您的目的,您实际上不需要每次有人对 java.c 进行更改时都进行更改,只有当 JavaVMInitArgs 或调用接口的某些其他关键方面发生更改时,您才真正需要更改它。

我确信,如果您提出并贡献了一种更优雅的选项处理解决方案,也许当 argv[0] 不是“java”时表现不同,那么开放 jdk 团队可能会采用您的方法并为您维护它,或者为了我们所有人。我确信有很多开发人员需要这样的功能。