Программное завершение Spring Boot приложения без закрытия VM

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для немедленного прекращения работы приложения Spring Boot можно использовать SpringApplication.exit в связке с ApplicationContext. Посмотрите на образец кода:

Java
Скопировать код
@Autowired
private ApplicationContext applicationContext;

public void shutdown() {
    int exitCode = SpringApplication.exit(applicationContext, () -> 0);
    System.exit(exitCode);
}

Метод shutdown() следует вызывать, когда пришло время остановить работу вашего приложения. Оно прекратит свою деятельность корректным образом.

Кинга Идем в IT: пошаговый план для смены профессии

Ваше приложение засыпает? Бессонница подкрадывается? Завершайте работу с достоинством!

Если наступило время завершить работу приложения и передать операционной системе конкретный код выхода, выполните реализацию интерфейса ExitCodeGenerator следующим образом:

Java
Скопировать код
public class CustomExitCode implements ExitCodeGenerator {
    @Override
    public int getExitCode() {
        // Здесь можно определить свою логику и вернуть, например, 42 – код, знакомый благодаря "Путешествию автостопом по галактике".
        return 42;
    }
}

@Autowired
private ApplicationContext context;

public void shutdownWithCustomCode() {
    int exitCode = SpringApplication.exit(context, new CustomExitCode());
    System.exit(exitCode);
}

Запустите shutdownWithCustomCode(), и приложение закончит свою деятельность вместе с передачей операционной системе кода возврата 42.

Овладейте ApplicationContext, прежде чем он овладеет вами

Если вам нравится контролировать жизненный цикл контекста приложения, обратите внимание на ConfigurableApplicationContext:

Java
Скопировать код
ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);

// Когда всё выполнено...

context.close(); // Этот метод заботится об освобождении ресурсов должным образом и не провоцирует остановку JVM.

Вы можете вызывать метод close() столько раз, сколько видите нужным; дополнительные вызовы на уже закрытом контексте не повлекут за собой последствий.

Управление процессом остановки работы как крёстный отец

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

Java
Скопировать код
@Component
public class ApplicationShutdownManager {

    @Autowired
    private ConfigurableApplicationContext context;

    public int initiateShutdown(int returnCode) {
        return SpringApplication.exit(context, () -> returnCode);
    }

}

Инъекция ApplicationShutdownManager требуется в определённых местах. Используйте initiateShutdown(), чтобы приложение завершило работу правильно.

Визуализация

Если вы всё ещё со мной, представьте себе приложение Spring Boot, как будто это космический корабль (🚀):

Пришло время возвращаться на Землю? Начинаем спуск:

Java
Скопировать код
@SpringBootApplication
public class HomeboundRocket {
  public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(HomeboundRocket.class, args);
    // Ваш код...

    // Время для спуска:
    context.close(); // Безопасная посадка. Задачи выполнены.
  }
}

Рассматривайте context.close() как нажатие кнопки "вернуться домой":

До: 🚀 в космосе, выполняющий миссию. После: 🚀 успешно приземлился после выполнения задания.

Безопасность на первом месте! Все процессы (потоки) должны быть корректно завершены.

Продвинутые рекомендации для упорных разработчиков

Удалённое завершение работы: контроль на расстоянии

Для удалённого завершения работы создайте сервис с определённым URL:

Java
Скопировать код
@RestController
public class ShutdownController {

    @Autowired
    ApplicationShutdownManager shutdownManager;

    @PostMapping("/shutdown-app")
    public void shutdownApp(@RequestParam int returnCode) {
        shutdownManager.initiateShutdown(returnCode);
    }
}

Теперь у вас есть возможность остановить приложение из любого места нашего большой мира.

Очистка после тестов: совсем не тривиально, но важно

Для поддержания порядка в интеграционных тестах используйте аннотацию @DirtiesContext. Она гарантирует, что контекст будет закрыт и удалён после каждого сценария тестирования:

Java
Скопировать код
@SpringBootTest
@DirtiesContext
public class ShutdownIntegrationTest {
    
    @Autowired
    private ApplicationShutdownManager shutdownManager;

    @Test
    public void testShutdown() {
        int returnCode = shutdownManager.initiateShutdown(0);
        assertEquals(0, returnCode);
    }
}

Благодаря этой аннотации каждый тест будет запускаться в очищенном контексте.

Упрощение работы с неуправляемыми потоками для спокойного завершения

Если у вас есть асинхронные задачи, рассмотрите возможность использования ExecutorServiceExitCodeGenerator. Он позволит где гарантированно и изящно прекратить все активные задачи:

Java
Скопировать код
@Autowired
private ExecutorService executorService;

@Bean
public ExitCodeGenerator executorServiceExitCodeGenerator() {
    return new ExecutorServiceExitCodeGenerator(executorService);
}

Это как колыбельная для ваших задач. Она подготавливает их к закрытию перед остановкой приложения.

Не волнуйтесь, только позвольте JVM работать дальше

Иногда возникает необходимость закрыть ApplicationContext, но при этом оставить JVM работающей. В таких случаях идеальным решением будет метод close():

Java
Скопировать код
context.close(); // Контекст закрыт, но JVM продолжает работать.

Таким образом, JVM сможет продолжить выполнение запланированных задач или процессов.

Полезные материалы

  1. Документация Spring Boot – наша основа знаний для программного завершения работы приложений Spring Boot.
  2. ExitCodeGenerator (Spring Boot API версии 3.2.2) – важный справочник для создания своих кодов выхода.
  3. Правильное завершение работы приложений Spring Boot – DZone – корректное руководство по завершению работы приложений.
  4. Spring Boot Admin – удобный инструмент для контроля и мониторинга приложений, включая процессы завершения работы.
  5. spring-boot-shutdown · GitHub Topics · GitHub – подборка репозиториев на GitHub, связанных с управлением жизненным циклом приложений Spring Boot.
  6. ConfigurableApplicationContext (Spring Framework API версии 6.1.3) – детальное описание по регистрации хуков завершения работы в Spring Framework и Spring Boot.