В этом посте мы рассмотрим общую потребность разработчиков 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);
}