В этом посте мы рассмотрим общую потребность разработчиков Java. Выполнять и управлять внешним процессом изнутри Java. Поскольку эта задача довольно распространена, мы решили найти библиотеку Java, которая поможет нам в этом.
Требования от такой библиотеки:
- Выполните процесс асинхронно.
- Возможность прервать выполнение процесса.
- Возможность дождаться завершения процесса.
- На выходе процесса уведомления.
- Возможность убить процесс в случае зависания.
- Получить код завершения процесса.
Родной JDK мало чем помогает. К счастью, у нас есть
Apache Commons Exe . На самом деле все гораздо проще, но все же не так просто, как мы надеялись. Мы написали небольшую обертку сверху.
Вот подпись метода, которую мы выставляем:
public static Future <Long> runProcess (финальная командная строка CommandLine, финальный обработчик ProcessExecutorHandler, финальный long watchdogTimeout) выдает IOException;
- Возвращает будущее <Long>. Это охватывает раздел 1,2,3,6.
- Экземпляр ProcessExecutorHandler передается в функцию. Этот экземпляр на самом деле является слушателем любого вывода процесса. Это покрывает раздел 4 в нашем требовании.
- И последнее, но не менее важное: вы предоставляете тайм-аут. Если выполнение процесса занимает больше времени, чем указано, вы предполагаете, что процесс завис, и завершите его. В этом случае код ошибки, возвращаемый процессом, будет -999.
Это оно! Реализация может быть найдена в фрагменте кода ниже. Наслаждаться.
import org.apache.commons.exec. *; import org.apache.commons.exec.Executor; импорт java.io.IOException; импорт java.util.concurrent. *; открытый класс ProcessExecutor { public static final Long WATCHDOG_EXIST_VALUE = -999L; public static Future <Long> runProcess (финальная командная строка CommandLine, финальный обработчик ProcessExecutorHandler, финальный long watchdogTimeout) выдает IOException { ExecutorService executor = Executors.newSingleThreadExecutor (); Future <Long> result = executor.submit (new ProcessCallable (watchdogTimeout, handler, commandline)); executor.shutdown (); вернуть результат; } закрытый статический класс ProcessCallable реализует Callable <Long> { частный длинный сторожевой тайм-аут; закрытый обработчик ProcessExecutorHandler; частная командная строка CommandLine; private ProcessCallable (long watchdogTimeout, обработчик ProcessExecutorHandler, командная строка CommandLine) { this.watchdogTimeout = watchdogTimeout; this.handler = обработчик; this.commandline = командная строка; } @Override public Long call () выдает исключение { Executor executor = new DefaultExecutor (); executor.setProcessDestroyer (новый ShutdownHookProcessDestroyer ()); ExecuteWatchdog watchDog = new ExecuteWatchdog (watchdogTimeout); executor.setWatchdog (Watchdog); executor.setStreamHandler (новый PumpStreamHandler (новый MyLogOutputStream (обработчик, true), новый MyLogOutputStream (обработчик, false))); Long exitValue; пытаться { exitValue = new Long (executor.execute (commandline)); } catch (ExecuteException e) { exitValue = new Long (e.getExitValue ()); } если (watchDog.killedProcess ()) { exitValue = WATCHDOG_EXIST_VALUE; } return exitValue; } } закрытый статический класс MyLogOutputStream extends LogOutputStream { закрытый обработчик ProcessExecutorHandler; приватное логическое предисловиеToStandardOutput; private MyLogOutputStream (обработчик ProcessExecutorHandler, логическое предисловиеToStandardOutput) { this.handler = обработчик; this.forewordToStandardOutput = forewordToStandardOutput; } @Override защищенная пустота processLine (строковая строка, уровень int) { if (forewordToStandardOutput) { handler.onStandardOutput (линия); } еще { handler.onStandardError (линия); } } } } // интерфейс. открытый интерфейс ProcessExecutorHandler { public void onStandardOutput (String msg); public void onStandardError (String msg); }
import org.apache.commons.exec. *;
import org.apache.commons.exec.Executor;
импорт java.io.IOException;
импорт java.util.concurrent. *;
открытый класс ProcessExecutor {
public static final Long WATCHDOG_EXIST_VALUE = -999L;
публичное статическое будущее
runProcess (финальная командная строка CommandLine, финальный обработчик ProcessExecutorHandler, финальный длинный watchdogTimeout) выдает IOException {
ExecutorService executor = Executors.newSingleThreadExecutor ();
return executor.submit (новый ProcessCallable (watchdogTimeout, обработчик, командная строка));
}
закрытый статический класс ProcessCallable реализует Callable
{
частный длинный сторожевой тайм-аут;
закрытый обработчик ProcessExecutorHandler;
частная командная строка CommandLine;
private ProcessCallable (long watchdogTimeout, обработчик ProcessExecutorHandler, командная строка CommandLine) {
this.watchdogTimeout = watchdogTimeout;
this.handler = обработчик;
this.commandline = командная строка;
}
@Override
public Long call () выдает исключение {
Executor executor = new DefaultExecutor ();
executor.setProcessDestroyer (новый ShutdownHookProcessDestroyer ());
ExecuteWatchdog watchDog = new ExecuteWatchdog (watchdogTimeout);
executor.setWatchdog (Watchdog);
executor.setStreamHandler (новый PumpStreamHandler (новый MyLogOutputStream (обработчик, true), новый MyLogOutputStream (обработчик, false)));
Long exitValue;
пытаться {
exitValue = new Long (executor.execute (commandline));
} catch (ExecuteException e) {
exitValue = new Long (e.getExitValue ());
}
если (watchDog.killedProcess ()) {
exitValue = WATCHDOG_EXIST_VALUE;
}
return exitValue;
}
}
закрытый статический класс MyLogOutputStream extends LogOutputStream {
закрытый обработчик ProcessExecutorHandler;
приватное логическое предисловиеToStandardOutput;
private MyLogOutputStream (обработчик ProcessExecutorHandler, логическое предисловиеToStandardOutput) {
this.handler = обработчик;
this.forewordToStandardOutput = forewordToStandardOutput;
}
@Override
защищенная пустота processLine (строковая строка, уровень int) {
if (forewordToStandardOutput) {
handler.onStandardOutput (линия);
}
еще {
handler.onStandardError (линия);
}
}
}
}
// интерфейс.
открытый интерфейс ProcessExecutorHandler {
public void onStandardOutput (String msg);
public void onStandardError (String msg);
}