«1. Обзор

В этом руководстве мы покажем, как программно перезапустить приложение Spring Boot.

Перезапуск нашего приложения может быть очень удобен в некоторых случаях:

    Перезагрузка файлов конфигурации при изменении какого-либо параметра Изменение текущего активного профиля во время выполнения Повторная инициализация контекста приложения по любой причине

Хотя в этой статье рассматриваются функциональные возможности перезапуск приложения Spring Boot, обратите внимание, что у нас также есть отличное руководство по завершению работы приложений Spring Boot.

Теперь давайте рассмотрим различные способы реализации перезапуска приложения Spring Boot.

2. Перезапустите, создав новый контекст

Мы можем перезапустить наше приложение, закрыв контекст приложения и создав новый контекст с нуля. Хотя этот подход довольно прост, есть некоторые тонкие детали, с которыми мы должны быть осторожны, чтобы заставить его работать.

Давайте посмотрим, как реализовать это в методе main нашего приложения Spring Boot:

@SpringBootApplication
public class Application {

    private static ConfigurableApplicationContext context;

    public static void main(String[] args) {
        context = SpringApplication.run(Application.class, args);
    }

    public static void restart() {
        ApplicationArguments args = context.getBean(ApplicationArguments.class);

        Thread thread = new Thread(() -> {
            context.close();
            context = SpringApplication.run(Application.class, args.getSourceArgs());
        });

        thread.setDaemon(false);
        thread.start();
    }
}

Как видно из приведенного выше примера, важно воссоздать контекст в отдельном потоке, не являющемся демоном, — таким образом мы предотвращаем закрытие JVM, вызванное методом close, из-за закрытия нашего приложения. В противном случае наше приложение остановилось бы, поскольку JVM не ждет завершения потоков демона, прежде чем завершить их.

Кроме того, давайте добавим конечную точку REST, через которую мы можем инициировать перезапуск:

@RestController
public class RestartController {
    
    @PostMapping("/restart")
    public void restart() {
        Application.restart();
    } 
}

Здесь мы добавили контроллер с методом сопоставления, который вызывает наш метод перезапуска.

Затем мы можем вызвать нашу новую конечную точку для перезапуска приложения:

curl -X POST localhost:port/restart

Конечно, если мы добавим такую ​​конечную точку в реальное приложение, нам также придется защитить ее.

3. Конечная точка перезапуска Actuator

Другой способ перезапустить наше приложение — использовать встроенную RestartEndpoint из Spring Boot Actuator.

Во-первых, давайте добавим необходимые зависимости Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-cloud-starter</artifactId>
</dependency>

Затем мы должны включить встроенную конечную точку перезапуска в нашем файле application.properties:

management.endpoint.restart.enabled=true

Теперь, когда мы все настроили , мы можем внедрить RestartEndpoint в нашу службу:

@Service
public class RestartService {
    
    @Autowired
    private RestartEndpoint restartEndpoint;
    
    public void restartApp() {
        restartEndpoint.restart();
    }
}

В приведенном выше коде мы используем bean-компонент RestartEndpoint для перезапуска нашего приложения. Это хороший способ перезапуска, потому что нам нужно вызвать только один метод, который сделает всю работу.

Как мы видим, использование RestartEndpoint — это простой способ перезапустить наше приложение. С другой стороны, у этого подхода есть недостаток, поскольку он требует добавления упомянутых библиотек. Если мы их еще не используем, это может быть слишком много накладных расходов только для этой функциональности. В этом случае мы можем придерживаться ручного подхода из предыдущего раздела, поскольку для этого требуется всего несколько строк кода.

4. Обновление контекста приложения

В некоторых случаях мы можем перезагрузить контекст приложения, вызвав его метод обновления.

Хотя этот метод может показаться многообещающим, только некоторые типы контекста приложения поддерживают обновление уже инициализированного контекста. Например, FileSystemXmlApplicationContext, GroovyWebApplicationContext и некоторые другие поддерживают его.

К сожалению, если мы попробуем это сделать в веб-приложении Spring Boot, мы получим следующую ошибку:

java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts:
just call 'refresh' once

Наконец, хотя некоторые типы контекста поддерживают множественные обновления, этого следует избегать. Причина в том, что метод обновления разработан как внутренний метод, используемый платформой для инициализации контекста приложения.

5. Заключение

В этой статье мы рассмотрели несколько различных способов программного перезапуска приложения Spring Boot.

Как всегда, исходный код примеров можно найти на GitHub.