Я пытаюсь написать самообновляющееся приложение Spring Boot 2.2.5
Я написал небольшое веб-приложение spring-boot-starter-web с RESTController для управления процессом обновления (я знаю, REST-пути не установлены должным образом, например /update/update...)
Процесс должен выглядеть следующим образом:
- Запустите приложение Spring-Boot с помощью самостоятельно доставленного AdoptOpenJDK из библиотеки приложений
- Проверьте, доступно ли обновление на сервере (http://localhost: 8080 / update / check )
- Загрузите обновление в локальный каталог и разархивируйте все файлы во временный "каталог обновлений. (http://localhost: 8080 / update / download )
- Выключение Spring-Boot-приложения, включая JVM (http://localhost: 8080 / update / update )
- Изменить папки приложения (заменить библиотеки и другие файлы)
- Запустить приложение так же, как оно было запущено в пункте 1 (с самостоятельной доставкой AdoptOpenJDK и params)
F или сейчас я попытался выполнить эту задачу, используя следующий учебник:
https://dzone.com/articles/programmatically-restart-java
В этом примере я могу нормально перезапустить свое приложение , Но мне нужно позаботиться о том, чтобы операционная система c Shell / Commands работала правильно. например, я не могу запустить его на Windows вместе с новым CMD-окном. Только если приложение запускается в фоновом режиме, я не получаю никаких ошибок или, по крайней мере, приложение запускается и отвечает.
Я также рассмотрел материал Spring Boot Actuator, но это в основном перезагрузка контекста, но мне нужно поменять ресурсы, используемые JVM, работающей в данный момент.
Итак, я хочу спросить: есть ли способ перезапустить мое Spring-Boot-приложение, включая параметры, обновив все файлы из приложения и перезапуск JVM?
Мой текущий код выглядит следующим образом:
SelfupdateApplication (Spring-Boot-Start-Class)
@SpringBootApplication
public class SelfupdateApplication {
public static void main(String[] args) {
SpringApplication.run(SelfupdateApplication.class, args);
}
public static void update() {
try {
SelfupdateApplication.restartApplication(null);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Sun property pointing the main class and its arguments. Might not be defined
* on non Hotspot VM implementations.
*/
public static final String SUN_JAVA_COMMAND = "sun.java.command";
/**
* Restart the current Java application
*
* @param runBeforeRestart some custom code to be run before restarting
* @throws IOException
*/
public static void restartApplication(Runnable runBeforeRestart) throws IOException {
try {
// java binary
String java = System.getProperty("java.home") + "/bin/java";
System.out.println("Java-Home: " + java);
// vm arguments
List<String> vmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
StringBuffer vmArgsOneLine = new StringBuffer();
for (String arg : vmArguments) {
// if it's the agent argument : we ignore it otherwise the
// address of the old application and the new one will be in conflict
if (!arg.contains("-agentlib")) {
vmArgsOneLine.append(arg);
vmArgsOneLine.append(" ");
}
}
// init the command to execute, add the vm args
final StringBuffer cmd = new StringBuffer("\"" + java + "\" " + vmArgsOneLine);
// program main and program arguments
String[] mainCommand = System.getProperty(SUN_JAVA_COMMAND).split(" ");
// program main is a jar
if (mainCommand[0].endsWith(".jar")) {
// if it's a jar, add -jar mainJar
cmd.append("-jar " + new File(mainCommand[0]).getPath());
} else {
// else it's a .class, add the classpath and mainClass
cmd.append("-cp \"" + System.getProperty("java.class.path") + "\" " + mainCommand[0]);
}
// finally add program arguments
for (int i = 1; i < mainCommand.length; i++) {
cmd.append(" ");
cmd.append(mainCommand[i]);
}
// execute the command in a shutdown hook, to be sure that all the
// resources have been disposed before restarting the application
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
Runtime.getRuntime().exec(cmd.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
});
// execute some custom code before restarting
if (runBeforeRestart != null) {
runBeforeRestart.run();
}
// exit
System.exit(0);
} catch (Exception e) {
// something went wrong
throw new IOException("Error while trying to restart the application", e);
}
}
}
RestController для вызова отдельных шагов
@RestController
@RequestMapping("/update")
public class UpdateController {
@GetMapping("/download")
public boolean download() {
File currentDir = new File(System.getProperty("user.dir"));
File destDir = new File(currentDir.getAbsolutePath() + File.separator + "update_lib");
File downloadDir = new File("C:/temp/selfupdate/someServer/update");
try {
FileUtils.copyDirectory(downloadDir, destDir);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
@GetMapping("/check")
public void check() {
// not relevant for now
SomeHelper.checkForUpdate();
}
@GetMapping("/update")
public void update() {
SelfupdateApplication.update();
}
@GetMapping("/restart")
public void restart() {
try {
SelfupdateApplication.restartApplication(null);
} catch (IOException e) {
e.printStackTrace();
}
}
@GetMapping("/alive")
public String alive() {
return "Yes i am still here ;-)";
}
@GetMapping("/shutdown")
public String shutdown() {
Thread thread = new Thread() {
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(0);
}
};
thread.start();
return "System shutdown initiated";
}
@GetMapping("/version")
public String version() {
return "0.0.1";
}
}
Спасибо за чтение, и я ценю ваши предложения!