Самостоятельное обновление приложения Spring-Boot - PullRequest
0 голосов
/ 02 апреля 2020

Я пытаюсь написать самообновляющееся приложение Spring Boot 2.2.5

Я написал небольшое веб-приложение spring-boot-starter-web с RESTController для управления процессом обновления (я знаю, REST-пути не установлены должным образом, например /update/update...)

Процесс должен выглядеть следующим образом:

  1. Запустите приложение Spring-Boot с помощью самостоятельно доставленного AdoptOpenJDK из библиотеки приложений
  2. Проверьте, доступно ли обновление на сервере (http://localhost: 8080 / update / check )
  3. Загрузите обновление в локальный каталог и разархивируйте все файлы во временный "каталог обновлений. (http://localhost: 8080 / update / download )
  4. Выключение Spring-Boot-приложения, включая JVM (http://localhost: 8080 / update / update )
  5. Изменить папки приложения (заменить библиотеки и другие файлы)
  6. Запустить приложение так же, как оно было запущено в пункте 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";
    }

}

Спасибо за чтение, и я ценю ваши предложения!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...