如何创建自定义 JVM 启动器?

How would one create a custom JVM launcher?

一直以来都有“如何在没有主方法的情况下启动应用程序”的问题,大多数情况下都是“你可以” t”。我注意到现在如何只需扩展 Application 即可启动 JavaFX 应用程序。我一直在使用类似于 Application.launch() 的方法,但在那种情况下,我总是将 main 方法视为样板代码。于是我又开始寻找答案。

我发现 this answer 将我们链接到我们可以了解如何创建我们自己的 JVM 启动器的地方,但遗憾的是这篇文章不再存在。我花了很长时间寻找任何可能提示我应该做什么的东西,但没有结果。

我的问题

如何创建自定义 JVM 启动器以根据扩展的内容启动应用程序?例如,假设一个项目 1 声明为 class:

class MyApplcation extends App {

} 

项目启动不需要main方法,因为它扩展了App。这不是问题,尽管这是我的目标。问题是 如何创建自定义 JVM 启动器?

我的猜测是它会涉及到使用某种基础,为我们提供某种骨架,但我不确定在哪里可以找到这样的东西。

FX 如何实现其应用程序执行模型Java

Java由于 JEP 153: Enhance the java command-line launcher to launch JavaFX applications 的实现,可以启动不包含 main 方法的 FX 应用程序。

这是对 openjdk 启动器逻辑的修改,以检查要启动的 class 是否扩展了应用程序,如果是,调用启动 JavaFX 特定启动器 Java 运行时和关联的线程,创建了一个 GUI window(在 JavaFX 术语中是一个阶段),然后,创建了 avaFX 应用程序的实例并根据应用程序调用 init 和 start 方法JavaFX application lifecycle rules.

通过代码跟踪实现:

  1. main.c for JVM invokes JLILaunch in java.c
  2. java.c looks for a Java class sun.launcher.LauncherHelper and calls into the java class using JNI, invoking the checkAndLoadMain 函数。
  3. 如果要启动的 class 没有 main 方法,但是 extend the JavaFX application class, a FXHelper class 是用启动参数创建的。
  4. 对 FXHelper 的引用通过 JNI returned 到 java.c。
  5. java.c invokes the main method on the FXHelper 通过 JNI。
  6. FXHelper uses reflection to invoke com.sun.javafx.application.LauncherImpl.launchApplication().
  7. JavaFX LauncherImpl 将设置应用程序 classloader,然后在应用程序的主要 class 上首先设置 try to invoke a main() 方法。
  8. 如果没有 main() 方法,JavaFX LauncherImpl 将 start up the JavaFX launcher thread
  9. 在启动器线程上,LauncherImpl 将 call init() on the JavaFX application
  10. 在 JavaFX 应用程序线程上,LauncherImpl 将 create a new Stage (window) and pass it to the start method of the application
  11. 当最后阶段关闭或JavaFX平台退出时,the stop method on the application is called由LauncherImpl。
  12. 所有调用跟踪 return 应用程序退出,因为无事可做。

如何自定义启动器

  1. 获取 sun.launcher.LauncherHelper 代码的副本。
  2. 忽略代码顶部的警告 "This is NOT part of any API supported by Sun Microsystems. If you write code that depends on this, you do so at your own risk. This code and its internal interfaces are subject to change or deletion without notice." 并开始修改代码。
  3. 创建您自己的 FXHelper 版本,它将调用您自己的 LauncherImpl 而不是 JavaFX 版本(如果目标主应用程序 class 扩展了您的应用程序框架 class 而不是 JavaFX 那个)。
  4. 编写您自己的 LauncherImpl,为您的应用程序设置 classloader,创建您的应用程序实例 class 并调用您想要的应用程序类型的任何启动入口点。
  5. 运行 您的应用程序,放置 sun.launcher.LauncherHelper 的被黑版本和您的 LauncherImpl on the boot class path,因此它们会被拾取而不是 [=93= 附带的默认版本].

示例启动命令,假设要启动的目标应用程序是 com.mycompany.MyApplication:

java -Xbootclasspath/p <launcher class directory> com.mycompany.MyApplication