将Java类作为子进程运行

原文链接:https://dzone.com/articles/running-a-java-class-as-a-subprocess

(想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程等待你来学习。完全免费哦! )

作为子进程运行Java类(不是jar)是我本周需要做的事情。更确切地说,我想在测试中生成一个新进程,而不是直接在测试中运行它(进程内)。我认为这不是什么花哨或复杂的事情。但是,这不是我以前需要做的事情,也不知道要编写的确切代码。

幸运的是,稍后快速谷歌搜索和一些Stack Overflow帖子,我找到了我需要的答案。虽然答案是存在的,但为了我自己和你的利益,我在这里重写它。

class JavaProcess {
  private JavaProcess() {
  }
  public static int exec(Class clazz, List<String> jvmArgs, List<String> args) 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 = clazz.getName();
    List<String> command = new ArrayList<>();
    command.add(javaBin);
    command.addAll(jvmArgs);
    command.add("-cp");
    command.add(classpath);
    command.add(className);
    command.addAll(args);
    ProcessBuilder builder = new ProcessBuilder(command);
    Process process = builder.inheritIO().start();
    process.waitFor();
    return process.exitValue();
  }
}

这个静态函数接受Class你想要执行的类以及类的main方法所期望的任何JVM参数和参数。访问这两组参数可以完全控制子进程的执行。例如,您可能希望以较低的堆空间执行您的类,以查看它在内存压力下的应对方式(这就是我需要的)。

请注意,为此,要执行的类需要具有main方法。这很重要。

访问Java可执行文件的路径(存储在其中javaBin)允许您使用与主应用程序相同的Java版本来执行子进程。如果javaBin被替换为"java",那么您冒着使用机器的默认Java版本执行子进程的风险。这很可能很好,很多时候。但是,可能存在不希望这种情况的情况。

一旦命令全部添加到command列表中,它们就会传递给ProcessBuilder。在ProcessBuilder采用此列表,并使用包含在它生成的命令每个值。command列表中的每个值都用空格分隔ProcessBuilder。其构造函数还有其他重载,其中一个包含一个字符串,您可以自己手动定义整个命令。这使您无需手动管理命令字符串的参数添加。

启动子进程时,IO将其传递给执行它的进程。这需要查看它产生的任何stdouts和stderrs。inheritIO是一种方便的方法,也可以通过调用链接以下代码来实现(也可以配置stdin子进程):

builder
    .redirectInput(ProcessBuilder.Redirect.INHERIT)
    .redirectOutput(ProcessBuilder.Redirect.INHERIT)
    .redirectError(ProcessBuilder.Redirect.INHERIT);

最后waitFor告诉执行线程等待生成的子进程完成。无论过程成功还是错误都无关紧要 - 只要子流程以某种方式结束。主要执行可以继续进行。该过程如何完成详细说明exitValue。例如,0通常表示成功执行并1详细说明无效的语法错误。还有许多其他退出代码,它们可以在不同的应用程序之间变化。

调用exec方法看起来如下所示:
JavaProcess.exec(MyProcess.class, List.of("-Xmx200m"), List.of(“argument”))

这将执行以下命令(或接近它的命令):
/Library/Java/JavaVirtualMachines/jdk-12.0.1.jdk/Contents/Home/bin/java -cp /playing-around-for-blogs MyProcess “argument”

我已经删除了很多包含classpath的路径,以保持它更整洁。你的看起来可能比这长得多。这真的取决于你的应用程序。上面命令中的路径是使其运行所需的最低限度(显然是为我的机器定制的)。

该exec方法相当灵活,有助于描述正在发生的事情。虽然,如果您希望在更广泛的情况下使其更具延展性和适用性,我建议ProcessBuilder从方法中返回自己。允许您在多个位置重用此代码,同时提供配置IO重定向的灵活性以及决定是在后台运行子进程还是阻塞并等待其完成的功能。这看起来像是这样的:

public static ProcessBuilder exec(Class clazz, List<String> jvmArgs, List<String> args) {
  String javaHome = System.getProperty("java.home");
  String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
  String classpath = System.getProperty("java.class.path");
  String className = clazz.getName();
  List<String> command = new ArrayList<>();
  command.add(javaBin);
  command.addAll(jvmArgs);
  command.add("-cp");
  command.add(classpath);
  command.add(className);
  command.addAll(args);
  return new ProcessBuilder(command);
}

通过使用这些函数中的任何一个(或两个),您现在可以运行应用程序类路径中存在的任何类。在我的情况下,这对于在集成测试中生成子进程非常有帮助,而无需预先构建任何jar。这允许控制JVM参数,例如子进程的内存,如果直接在现有进程内运行,则无法配置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值