在本文中,我们将介绍Java开发人员的常见需求。 从Java内部执行和管理外部流程。 由于这项任务很常见,因此我们着手寻找一个Java库来帮助我们完成它。
该库的要求是:
- 异步执行该过程。
- 能够中止流程执行。
- 等待流程完成的能力。
- 处理中的输出通知。
- 能够在进程挂起时终止进程。
- 获取流程退出代码。
本地JDK并没有太大帮助。 幸运的是,我们有Apache Commons Exec 。 确实,这要容易得多,但仍不如我们希望的那样简单。 我们在上面写了一个小包装纸。
这是我们公开的方法签名:
1: public static Future<Long> runProcess(final CommandLine commandline, final ProcessExecutorHandler handler, final long watchdogTimeout) throws IOException;
- 它返回一个Future <Long>。 这涵盖了第1,2,3,6节。
- ProcessExecutorHandler的实例传递给该函数。 该实例实际上是任何进程输出的侦听器。 这涵盖了我们要求中的第4节。
- 最后但并非最不重要的一点是您要提供超时。 如果进程执行所花的时间超过了上述超时时间,则假定进程已挂起,然后将其终止。 在这种情况下,进程返回的错误代码将为-999。
而已! 这是方法植入。 请享用。
import org.apache.commons.exec.*;import org.apache.commons.exec.Executor;import java.io.IOException;import java.util.concurrent.*;public class ProcessExecutor {public static final Long WATCHDOG_EXIST_VALUE = -999L;public static Future<Long> runProcess(final CommandLine commandline, final ProcessExecutorHandler handler, final long watchdogTimeout) throws IOException{ExecutorService executor = Executors.newSingleThreadExecutor();return executor.submit(new ProcessCallable(watchdogTimeout, handler, commandline));}private static class ProcessCallable implements Callable<Long>{private long watchdogTimeout;private ProcessExecutorHandler handler;private CommandLine commandline;private ProcessCallable(long watchdogTimeout, ProcessExecutorHandler handler, CommandLine commandline) {this.watchdogTimeout = watchdogTimeout;this.handler = handler;this.commandline = commandline;}@Overridepublic Long call() throws Exception {Executor executor = new DefaultExecutor();executor.setProcessDestroyer(new ShutdownHookProcessDestroyer());ExecuteWatchdog watchDog = new ExecuteWatchdog(watchdogTimeout);executor.setWatchdog(watchDog);executor.setStreamHandler(new PumpStreamHandler(new MyLogOutputStream(handler, true),new MyLogOutputStream(handler, false)));Long exitValue;try {exitValue = new Long(executor.execute(commandline));} catch (ExecuteException e) {exitValue = new Long(e.getExitValue());}if(watchDog.killedProcess()){exitValue =WATCHDOG_EXIST_VALUE;}return exitValue;}}private static class MyLogOutputStream extends LogOutputStream{private ProcessExecutorHandler handler;private boolean forewordToStandardOutput;private MyLogOutputStream(ProcessExecutorHandler handler, boolean forewordToStandardOutput) {this.handler = handler;this.forewordToStandardOutput = forewordToStandardOutput;}@Overrideprotected void processLine(String line, int level) {if (forewordToStandardOutput){handler.onStandardOutput(line);}else{handler.onStandardError(line);}}}public static void main(String[] args) throws IOException {CommandLine cl = CommandLine.parse("test.bat");Future<Long> exitValue = runProcess(cl, new ProcessExecutorHandler() {@Overridepublic void onStandardOutput(String msg) {System.out.println("output msg = " + msg);}@Overridepublic void onStandardError(String msg) {System.out.println("error msg = " + msg);}}, 1);try {Long aVoid = exitValue.get();System.out.println("Finished with " + aVoid);} catch (InterruptedException e) {e.printStackTrace(); //To change body of catch statement use File | ngs | File Templates.} catch (ExecutionException e) {e.printStackTrace(); //To change body of catch statement use File | ngs | File Templates.}}}
参考:在DeveloperLife博客上,从我们的JCG合作伙伴 Nadav Azaria 执行可从Java执行的命令行 。
翻译自: https://www.javacodegeeks.com/2013/01/executing-a-command-line-executable-from-java.html