我正在尝试按照此处所示的方法通过代码在单独的 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 应用程序:
将所有内容放在模块路径上,包括 JavaFX 模块和您的模块。
- 这是理想的情况,但并不总是可能/可行(例如,由于不兼容的依赖项)。
将 JavaFX 模块放在模块路径上,将您自己的代码放在类路径上。
- 此配置需要使用
--add-modules
.
- 此配置需要使用
将所有内容放在类路径上,包括 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/