Программное завершение Spring Boot приложения без закрытия VM
Быстрый ответ
Для немедленного прекращения работы приложения Spring Boot можно использовать SpringApplication.exit
в связке с ApplicationContext
. Посмотрите на образец кода:
@Autowired
private ApplicationContext applicationContext;
public void shutdown() {
int exitCode = SpringApplication.exit(applicationContext, () -> 0);
System.exit(exitCode);
}
Метод shutdown()
следует вызывать, когда пришло время остановить работу вашего приложения. Оно прекратит свою деятельность корректным образом.
Ваше приложение засыпает? Бессонница подкрадывается? Завершайте работу с достоинством!
Если наступило время завершить работу приложения и передать операционной системе конкретный код выхода, выполните реализацию интерфейса ExitCodeGenerator
следующим образом:
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
:
ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
// Когда всё выполнено...
context.close(); // Этот метод заботится об освобождении ресурсов должным образом и не провоцирует остановку JVM.
Вы можете вызывать метод close()
столько раз, сколько видите нужным; дополнительные вызовы на уже закрытом контексте не повлекут за собой последствий.
Управление процессом остановки работы как крёстный отец
Если вам нужно централизовать логику завершения работы в больших приложениях, рекомендуется использовать ApplicationShutdownManager
:
@Component
public class ApplicationShutdownManager {
@Autowired
private ConfigurableApplicationContext context;
public int initiateShutdown(int returnCode) {
return SpringApplication.exit(context, () -> returnCode);
}
}
Инъекция ApplicationShutdownManager
требуется в определённых местах. Используйте initiateShutdown()
, чтобы приложение завершило работу правильно.
Визуализация
Если вы всё ещё со мной, представьте себе приложение Spring Boot, как будто это космический корабль (🚀):
Пришло время возвращаться на Землю? Начинаем спуск:
@SpringBootApplication
public class HomeboundRocket {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(HomeboundRocket.class, args);
// Ваш код...
// Время для спуска:
context.close(); // Безопасная посадка. Задачи выполнены.
}
}
Рассматривайте context.close()
как нажатие кнопки "вернуться домой":
До: 🚀 в космосе, выполняющий миссию. После: 🚀 успешно приземлился после выполнения задания.
Безопасность на первом месте! Все процессы (потоки) должны быть корректно завершены.
Продвинутые рекомендации для упорных разработчиков
Удалённое завершение работы: контроль на расстоянии
Для удалённого завершения работы создайте сервис с определённым URL:
@RestController
public class ShutdownController {
@Autowired
ApplicationShutdownManager shutdownManager;
@PostMapping("/shutdown-app")
public void shutdownApp(@RequestParam int returnCode) {
shutdownManager.initiateShutdown(returnCode);
}
}
Теперь у вас есть возможность остановить приложение из любого места нашего большой мира.
Очистка после тестов: совсем не тривиально, но важно
Для поддержания порядка в интеграционных тестах используйте аннотацию @DirtiesContext
. Она гарантирует, что контекст будет закрыт и удалён после каждого сценария тестирования:
@SpringBootTest
@DirtiesContext
public class ShutdownIntegrationTest {
@Autowired
private ApplicationShutdownManager shutdownManager;
@Test
public void testShutdown() {
int returnCode = shutdownManager.initiateShutdown(0);
assertEquals(0, returnCode);
}
}
Благодаря этой аннотации каждый тест будет запускаться в очищенном контексте.
Упрощение работы с неуправляемыми потоками для спокойного завершения
Если у вас есть асинхронные задачи, рассмотрите возможность использования ExecutorServiceExitCodeGenerator
. Он позволит где гарантированно и изящно прекратить все активные задачи:
@Autowired
private ExecutorService executorService;
@Bean
public ExitCodeGenerator executorServiceExitCodeGenerator() {
return new ExecutorServiceExitCodeGenerator(executorService);
}
Это как колыбельная для ваших задач. Она подготавливает их к закрытию перед остановкой приложения.
Не волнуйтесь, только позвольте JVM работать дальше
Иногда возникает необходимость закрыть ApplicationContext
, но при этом оставить JVM работающей. В таких случаях идеальным решением будет метод close()
:
context.close(); // Контекст закрыт, но JVM продолжает работать.
Таким образом, JVM сможет продолжить выполнение запланированных задач или процессов.
Полезные материалы
- Документация Spring Boot – наша основа знаний для программного завершения работы приложений Spring Boot.
- ExitCodeGenerator (Spring Boot API версии 3.2.2) – важный справочник для создания своих кодов выхода.
- Правильное завершение работы приложений Spring Boot – DZone – корректное руководство по завершению работы приложений.
- Spring Boot Admin – удобный инструмент для контроля и мониторинга приложений, включая процессы завершения работы.
- spring-boot-shutdown · GitHub Topics · GitHub – подборка репозиториев на GitHub, связанных с управлением жизненным циклом приложений Spring Boot.
- ConfigurableApplicationContext (Spring Framework API версии 6.1.3) – детальное описание по регистрации хуков завершения работы в Spring Framework и Spring Boot.