java - 在单独的 JVM 上执行新的 JavaFX 应用程序
问题描述
我正在尝试按照此处说明的方法通过代码在单独的 JVM 上启动新进程: 在单独的进程中执行 Java 应用程序
我正在使用的代码如下(取自上面的问题):
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 应用程序,并且上面的代码会生成以下错误:
Error: JavaFX runtime components are missing, and are required to run this application
因此,为了添加 JavaFX 模块,我尝试在 的声明中包含 --module-path 和 --add-modules 命令builder
,我什至尝试复制和粘贴整个执行命令,但我一直收到另一个错误:
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。
- 警告:这种方法是明确不支持的。
- 使用此配置,您的主类不能是
使用的命令行将ProcessBuilder
取决于您的应用程序使用的配置。您还必须考虑通过命令行传递的任何其他选项,例如默认编码或语言环境。不幸的是,您的问题没有提供足够的信息来说明究竟出了什么问题。你提到的错误让我觉得你正在使用第三种配置,但我不能确定。
也就是说,我将给出一些从应用程序内部启动相同应用程序的示例;您应该能够修改内容以满足您的需求。注意我在测试以下代码时使用了 Java/JavaFX 13.0.1。
配置#1
将所有内容放在模块路径上。
模块信息.java:
module app {
requires javafx.controls;
exports com.example.app to
javafx.graphics;
}
主.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 模块放在模块路径上,将代码放在类路径上。
主.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
.
启动器.java:
package com.example.app;
import javafx.application.Application;
public class Launcher {
public static void main(String[] args) {
Application.launch(Main.class, args);
}
}
主.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 和上述代码的路径。
推荐阅读
- c# - 实体框架:如何在不重新添加父级的情况下更新子级
- javascript - 用于 API 的 NODEJS Express 应用程序生成器
- javascript - 不使用反转功能反转数字
- python - 如何在 Python 中使用 Dict 创建多个组合列表
- php - PHP在浏览器中显示
- html - 响应式元素停止缩小并离开屏幕
- swift - 如何在 Swift 4 中将服务器 UTC 时间转换为本地时间?
- android - 访问联系人后如何在列表视图中选择多个值
- python - 尝试从华为调制解调器读取消息时出现错误 125002
- php - Mapbox:如何在 Mapbox 输入搜索自动完成中获取地址值并使用 PHP 在 Mysql 表中插入?