[关闭]
@TedZhou 2020-08-25T11:05:06.000000Z 字数 4121 阅读 667

Java commons-exec 执行外部命令

java commons exec shell process


Java创建子进程(Process)执行外部命令底层的方法是new ProcessBuilder().start()或Runtime.getRuntime().exec()。

Apache commons-exec对底层进行封装,提供了更加详细的设置和监控方法。

pom.xml

  1. <dependency>
  2. <groupId>org.apache.commons</groupId>
  3. <artifactId>commons-exec</artifactId>
  4. <version>1.3</version>
  5. </dependency>

CmdHelper.java

  1. import java.io.IOException;
  2. import java.io.OutputStream;
  3. import java.util.concurrent.CompletableFuture;
  4. import org.apache.commons.exec.CommandLine;
  5. import org.apache.commons.exec.DefaultExecutor;
  6. import org.apache.commons.exec.ExecuteWatchdog;
  7. import org.apache.commons.exec.PumpStreamHandler;
  8. import org.apache.commons.exec.ShutdownHookProcessDestroyer;
  9. public class CmdHelper {
  10. /**
  11. * 执行外部命令,等待返回结果
  12. *
  13. * @param commandLine: 命令行
  14. * @param out: 输出流,为空默认标准输出
  15. * @param timeout: 超时,不大于0则不限超时
  16. * @return CmdHandler based on DefaultExecuteResultHandler
  17. */
  18. public static CmdHandler run(CommandLine commandLine, OutputStream out, long timeout) {
  19. PumpStreamHandler pumpStreamHandler = null;
  20. if (null == out) {
  21. pumpStreamHandler = new PumpStreamHandler();
  22. } else {
  23. pumpStreamHandler = new PumpStreamHandler(out);
  24. }
  25. DefaultExecutor executor = new DefaultExecutor();
  26. CmdHandler cmdHandler = new CmdHandler(executor);
  27. executor.setStreamHandler(pumpStreamHandler);
  28. ShutdownHookProcessDestroyer processDestroyer = new ShutdownHookProcessDestroyer();
  29. executor.setProcessDestroyer(processDestroyer);// 随主进程退出
  30. if (timeout <= 0) {
  31. timeout = ExecuteWatchdog.INFINITE_TIMEOUT;
  32. }
  33. ExecuteWatchdog watchdog = new ExecuteWatchdog(timeout);
  34. executor.setWatchdog(watchdog);// 控制超时
  35. try {
  36. executor.execute(commandLine, cmdHandler);
  37. cmdHandler.waitFor();// 等待返回结果
  38. } catch (IOException | InterruptedException e) {
  39. e.printStackTrace();
  40. }
  41. return cmdHandler;
  42. }
  43. /**
  44. * 异步执行外部命令
  45. *
  46. * @param commandLine: 命令行
  47. * @param out: 输出流,为空默认标准输出
  48. * @param timeout: 超时,不大于0则不限超时
  49. * @return CompletableFuture<CmdHandler>
  50. */
  51. public static CompletableFuture<CmdHandler> exec(CommandLine commandLine, OutputStream out, long timeout) {
  52. CompletableFuture<CmdHandler> cf = new CompletableFuture<>();
  53. PumpStreamHandler pumpStreamHandler = null;
  54. if (null == out) {
  55. pumpStreamHandler = new PumpStreamHandler();
  56. } else {
  57. pumpStreamHandler = new PumpStreamHandler(out);
  58. }
  59. DefaultExecutor executor = new DefaultExecutor();
  60. CmdHandler cmdHandler = new CmdHandler(executor);
  61. cmdHandler.setCallback(() -> {
  62. cf.complete(cmdHandler);// 执行完成后回调
  63. });
  64. executor.setStreamHandler(pumpStreamHandler);
  65. ShutdownHookProcessDestroyer processDestroyer = new ShutdownHookProcessDestroyer();
  66. executor.setProcessDestroyer(processDestroyer);// 随主进程退出
  67. if (timeout <= 0) {
  68. timeout = ExecuteWatchdog.INFINITE_TIMEOUT;
  69. }
  70. ExecuteWatchdog watchdog = new ExecuteWatchdog(timeout);
  71. executor.setWatchdog(watchdog);// 控制超时
  72. try {
  73. executor.execute(commandLine, cmdHandler);
  74. } catch (IOException e) {
  75. e.printStackTrace();
  76. }
  77. return cf;
  78. }
  79. public static void main(String[] args) throws InterruptedException {
  80. CommandLine command = CommandLine.parse("ping 127.0.0.1 -t");
  81. // 测试同步执行
  82. CmdHandler result = CmdHelper.run(command, null, 3000);
  83. System.out.println(result.resultString());
  84. // 测试异步执行
  85. CmdHelper.exec(command, null, 0).thenAccept(cmdHandler -> {
  86. System.out.println(cmdHandler.resultString());
  87. });
  88. }
  89. }

CmdHandler.java

  1. import org.apache.commons.exec.DefaultExecuteResultHandler;
  2. import org.apache.commons.exec.ExecuteException;
  3. import org.apache.commons.exec.ExecuteWatchdog;
  4. import org.apache.commons.exec.Executor;
  5. public class CmdHandler extends DefaultExecuteResultHandler {
  6. Executor executor;
  7. Runnable callback;
  8. public CmdHandler(Executor executor) {
  9. this.executor = executor;
  10. }
  11. public void setCallback(Runnable callback) {
  12. this.callback = callback;
  13. }
  14. public Executor getExecutor() {
  15. return this.executor;
  16. }
  17. public ExecuteWatchdog getWatchdog() {
  18. if (this.executor == null) return null;
  19. return this.executor.getWatchdog();
  20. }
  21. public String resultString() {
  22. String retMsg = "complete";
  23. if (this.getException() != null) {
  24. ExecuteWatchdog watchdog = this.getWatchdog();
  25. if (watchdog != null && watchdog.killedProcess()) {
  26. retMsg = "timeout";
  27. } else {
  28. retMsg = this.getException().getMessage();
  29. }
  30. }
  31. return this.getExitValue() + ":" + retMsg;
  32. }
  33. @Override
  34. public void onProcessComplete(int exitValue) {
  35. super.onProcessComplete(exitValue);
  36. if (callback != null) {
  37. callback.run();
  38. }
  39. }
  40. @Override
  41. public void onProcessFailed(ExecuteException e) {
  42. super.onProcessFailed(e);
  43. if (callback != null) {
  44. callback.run();
  45. }
  46. }
  47. }

参考

  1. https://www.cnblogs.com/kingcucumber/p/3180146.html
  2. https://www.jianshu.com/p/73aaec23009d
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注