java - 在单独的 JVM 上执行新的 JavaFX 应用程序

标签 java exception javafx jvm

我正在尝试按照此处所示的方法通过代码在单独的 JVM 上启动一个新进程: Executing a Java application in a separate process

我使用的代码如下(取自上面的问题):

public static int exec(Class klass) throws IOException, InterruptedException {
        String javaHome = System.getProperty("java.home");
        String javaBin = javaHome +
                File.separator + "bin" +
                File.separator + "java";
        String classpath = System.getProperty("java.class.path");
        String className = klass.getName();

        ProcessBuilder builder = new ProcessBuilder(javaBin,"-cp",classpath,className);
        Process process = builder.inheritIO().start();
        process.waitFor();
        return process.exitValue();
    }

...其中 klass 是我要启动的类。 这适用于正常的 Java 进程,但问题是我正在尝试启动 JavaFX 应用程序,并且上面的代码生成以下错误:

错误:缺少 JavaFX 运行时组件,并且需要运行此应用程序

因此,为了添加 JavaFX 模块,我尝试在 builder 的声明中包含 --module-path 和 --add-modules 命令,我什至尝试复制并粘贴整个执行命令,并且我不断收到另一个错误:

Unrecognized option: (command string with modules)
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

我该如何解决这个问题?

如果需要详细信息,请告诉我。

最佳答案

自从模块出现以来,至少有三种不同的方式可以配置 JavaFX 应用程序:

  1. 将所有内容放在模块路径上,包括 JavaFX 模块和您的模块。

    • 这是理想的情况,但并不总是可能/可行(例如,由于不兼容的依赖项)。
  2. 将 JavaFX 模块放在模块路径上,将您自己的代码放在类路径上。

    • 此配置需要使用 --add-modules .
  3. 将所有内容放在类路径上,包括 JavaFX 模块和您自己的代码。

    • 使用此配置,您的主类不能成为 Application 的子类型。否则,您会收到问题中提到的错误:“错误:缺少 JavaFX 运行时组件,并且需要运行此应用程序”。
    • 此配置可以轻松使用所谓的 fat/uber JAR。
    • 警告:此方法是 explicitly unsupported .

ProcessBuilder一起使用的命令行将取决于您的应用程序使用的配置。您还必须考虑通过命令行传递的任何其他选项,例如默认编码或区域设置。不幸的是,您的问题没有提供足够的信息来说明到底出了什么问题。您提到的错误让我认为您正在使用第三种配置,但我不能确定。

也就是说,我将给出一些从应用程序内部启动相同应用程序的示例;您应该能够修改内容以满足您的需求。请注意,我在测试以下代码时使用了 Java/JavaFX 13.0.1。


配置#1

将所有内容放在模块路径上。

module-info.java:

module app {
  requires javafx.controls;

  exports com.example.app to
      javafx.graphics;
}

Main.java:

package com.example.app;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import static java.lang.System.getProperty;

public class Main extends Application {

  private static void launchProcess() {
    try {
      new ProcessBuilder(
              Path.of(getProperty("java.home"), "bin", "java").toString(),
              "--module-path",
              getProperty("jdk.module.path"),
              "--module",
              getProperty("jdk.module.main") + "/" + getProperty("jdk.module.main.class"))
          .inheritIO()
          .start();
    } catch (IOException ex) {
      throw new UncheckedIOException(ex);
    }
  }

  @Override
  public void start(Stage primaryStage) {
    Button launchBtn = new Button("Launch process");
    launchBtn.setOnAction(
        event -> {
          event.consume();
          launchProcess();
        });
    primaryStage.setScene(new Scene(new StackPane(launchBtn), 500, 300));
    primaryStage.setTitle("Multi-Process Example");
    primaryStage.show();
  }
}

命令行:

java --module-path <PATH> --module app/com.example.app.Main

将“<PATH> ”替换为包含 JavaFX 模块和上述模块的路径。


配置#2

将 JavaFX 模块放在模块路径上,将代码放在类路径上。

Main.java:

package com.example.app;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import static java.lang.System.getProperty;

public class Main extends Application {

  private static void launchProcess() {
    try {
      new ProcessBuilder(
              Path.of(getProperty("java.home"), "bin", "java").toString(),
              "--module-path",
              getProperty("jdk.module.path"),
              "--add-modules",
              "javafx.controls",
              "--class-path",
              getProperty("java.class.path"),
              Main.class.getName())
          .inheritIO()
          .start();
    } catch (IOException ex) {
      throw new UncheckedIOException(ex);
    }
  }

  @Override
  public void start(Stage primaryStage) {
    Button launchBtn = new Button("Launch process");
    launchBtn.setOnAction(
        event -> {
          event.consume();
          launchProcess();
        });
    primaryStage.setScene(new Scene(new StackPane(launchBtn), 500, 300));
    primaryStage.setTitle("Multi-Process Example");
    primaryStage.show();
  }
}

命令行:

java --module-path <M_PATH> --add-modules javafx.controls --class-path <C_PATH> com.example.app.Main

将“<M_PATH> ”替换为包含 JavaFX 模块的路径,并将“<C_PATH> ”替换为包含上述代码的路径。


配置#3

将所有内容放在类路径上。请注意,主类(现在 Launcher )不是 Application 的子类。 .

Launcher.java:

package com.example.app;

import javafx.application.Application;

public class Launcher {

  public static void main(String[] args) {
    Application.launch(Main.class, args);
  }
}

Main.java:

package com.example.app;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import static java.lang.System.getProperty;

public class Main extends Application {

  private static void launchProcess() {
    try {
      new ProcessBuilder(
              Path.of(getProperty("java.home"), "bin", "java").toString(),
              "--class-path",
              getProperty("java.class.path"),
              Launcher.class.getName())
          .inheritIO()
          .start();
    } catch (IOException ex) {
      throw new UncheckedIOException(ex);
    }
  }

  @Override
  public void start(Stage primaryStage) {
    Button launchBtn = new Button("Launch process");
    launchBtn.setOnAction(
        event -> {
          event.consume();
          launchProcess();
        });
    primaryStage.setScene(new Scene(new StackPane(launchBtn), 500, 300));
    primaryStage.setTitle("Multi-Process Example");
    primaryStage.show();
  }
}

命令行:

java --class-path <PATH> com.example.app.Launcher

将“<PATH> ”替换为包含 JavaFX JAR 和上述代码的路径。

关于java - 在单独的 JVM 上执行新的 JavaFX 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59605956/

相关文章:

java - Spring Boot 多个 servlet 错误

java - 哪个msn java库比较好?

c# - System.Reflection.TargetInvocationException;需要帮助理解

objective-c - 核心数据和 NSEntityDescription

javaFX 帧图像

java - 从控制台菜单调用继承该方法的类的方法

Java 格式 double 到最小精度的字符串

python - 如何使用线程进行客户端服务器应用程序的功能测试?

java - 属性 "style"不存在或为只读

java - JavaFX 的标题面板(矩形命名区域控件)?