У меня есть сервер, написанный на Java, который работает как служба Windows (спасибо Install4J). Я хочу, чтобы эта служба могла загружать последнюю версию файла JAR, из которого он запускается, и запускать новый код. Дело в том, что я не хочу, чтобы служба Windows полностью закрывалась.
В идеале я бы сделал это с помощью вызова exec () в стиле unix, чтобы остановить текущую версию и запустить новую. Как мне лучше всего этого добиться?




Насколько мне известно, в Java нет возможности сделать это.
Я полагаю, вы могли бы обойти это, используя команду start () Java Runtime.exec или ProcessBuilder (которая запускает новые процессы), а затем позволяя текущему концу ... состояние документов
The subprocess is not killed when there are no more references to the Process object, but rather the subprocess continues executing asynchronously.
Я предполагаю, что то же самое верно, если родитель завершает работу и собирается сборщиком мусора.
Загвоздка в том, что у процесса Runtime.exec больше не будет допустимых потоков входа, выхода и ошибок.
Общий подход:
import java.io.BufferedInputStream;
import java.util.Arrays;
public class ProcessSpawner {
public static void main(String[] args) {
//You can change env variables and working directory, and
//have better control over arguments.
//See [ProcessBuilder javadocs][1]
ProcessBuilder builder = new ProcessBuilder("ls", "-l");
try {
Process p = builder.start();
//here we just echo stdout from the process to java's stdout.
//of course, this might not be what you're after.
BufferedInputStream stream =
new BufferedInputStream(p.getInputStream());
byte[] b = new byte[80];
while(stream.available() > 0) {
stream.read(b);
String s = new String(b);
System.out.print(s);
Arrays.fill(b, (byte)0);
}
//exit with the exit code of the spawned process.
System.exit(p.waitFor());
} catch(Exception e) {
System.err.println("Exception: "+e.getMessage());
System.exit(1);
}
}
}
Вот сложный, но портативный способ.
Разделите свой код на две банки. Одна очень маленькая банка предназначена только для управления запуском процесса. Он создает ClassLoader, который содержит другую банку в своем пути к классам.
Когда вы хотите загрузить новую версию, вы завершаете все потоки, выполняющие код из старого jar. Удалите все ссылки на экземпляры классов из старого файла jar. Удалите все ссылки на ClassLoader, который загрузил старый jar. На этом этапе, если вы ничего не пропустили, старые классы и ClassLoader должны иметь право на сборку мусора.
Теперь вы начинаете с нового экземпляра ClassLoader, указывающего на новую банку, и перезапускаете код приложения.
Вы можете использовать встроенную функцию перезагрузки, например, Tomcat, Jetty или JBoss, их можно запускать как службу, и вам не нужно использовать их как веб-контейнер или контейнер Java EE.
Другие варианты - OSGi и функция загрузки вашего собственного класса.
Но помните о перезагрузке в производственной среде. Это не всегда лучшее решение.
Оболочка служб Java делает это и многое другое.