1. Обзор
Управление жизненным циклом приложения Spring Boot очень важно для готовой к работе системы. Контейнер Spring обрабатывает создание, инициализацию и уничтожение всех компонентов с помощью ApplicationContext.
Акцент в этой записи делается на фазе разрушения жизненного цикла. Более конкретно, мы рассмотрим различные способы завершения работы приложения Spring Boot.
Чтобы узнать больше о том, как настроить проект с помощью Spring Boot, ознакомьтесь со статьей Spring Boot Starter или просмотрите конфигурацию Spring Boot .
2. Конечная точка завершения работы
По умолчанию в приложении Spring Boot включены все конечные точки, кроме /shutdown ; это, естественно, часть конечных точек Привода .
Вот зависимость Maven для их настройки:
org.springframework.boot spring-boot-starter-actuator
И, если мы хотим также настроить поддержку безопасности, нам нужно:
org.springframework.boot spring-boot-starter-security
Наконец, мы включаем конечную точку завершения работы в файле application.properties :
management.endpoints.web.exposure.include=* management.endpoint.shutdown.enabled=true endpoints.shutdown.enabled=true
Обратите внимание, что мы также должны предоставить любые конечные точки привода, которые мы хотим использовать. В приведенном выше примере мы раскрыли все конечные точки привода, которые будут включать конечную точку /shutdown .
Чтобы закрыть приложение Spring Boot, мы просто вызываем метод POST, подобный этому :
curl -X POST localhost:port/actuator/shutdown
В этом вызове порт представляет порт привода.
3. Закройте контекст приложения
Мы также можем вызвать метод close() непосредственно из контекста приложения.
Давайте начнем с примера создания контекста и его закрытия:
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class).web(WebApplicationType.NONE).run(); System.out.println("Spring Boot application started"); ctx.getBean(TerminateBean.class); ctx.close();
Это уничтожает все бобы, освобождает замки, а затем закрывает фабрику бобов . Для проверки завершения работы приложения мы используем стандартный обратный вызов жизненного цикла Spring с аннотацией @PreDestroy :
public class TerminateBean { @PreDestroy public void onDestroy() throws Exception { System.out.println("Spring Container is destroyed!"); } }
Мы также должны добавить боб этого типа:
@Configuration public class ShutdownConfig { @Bean public TerminateBean getTerminateBean() { return new TerminateBean(); } }
Вот результат после выполнения этого примера:
Spring Boot application started Closing [email protected] DefaultLifecycleProcessor - Stopping beans in phase 0 Unregistering JMX-exposed beans on shutdown Spring Container is destroyed!
Здесь важно иметь в виду: при закрытии контекста приложения родительский контекст не затрагивается из-за отдельных жизненных циклов .
3.1. Закройте текущий контекст приложения
В приведенном выше примере мы создали контекст дочернего приложения, а затем использовали метод close () , чтобы уничтожить его.
Если мы хотим закрыть текущий контекст, одним из решений является простой вызов конечной точки привода /shutdown .
Однако мы также можем создать вашу собственную конечную точку:
@RestController public class ShutdownController implements ApplicationContextAware { private ApplicationContext context; @PostMapping("/shutdownContext") public void shutdownContext() { ((ConfigurableApplicationContext) context).close(); } @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException { this.context = ctx; } }
Здесь мы добавили контроллер, который реализует интерфейс ApplicationContextAware и переопределяет метод setter для получения текущего контекста приложения. Затем в методе сопоставления мы просто вызываем метод close () .
Затем мы можем вызвать нашу новую конечную точку, чтобы закрыть текущий контекст:
curl -X POST localhost:port/shutdownContext
Конечно, если вы добавите такую конечную точку в реальное приложение, вам также захочется защитить ее.
4. Выйдите из приложения Пружины
Spring Application регистрирует shutdown hook в JVM, чтобы убедиться, что приложение завершает работу надлежащим образом.
Бобы могут реализовать Генератор кода выхода интерфейс для возврата определенного кода ошибки:
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class) .web(WebApplicationType.NONE).run(); int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() { @Override public int getExitCode() { // return the error code return 0; } }); System.exit(exitCode);
Тот же код с применением Java 8 lambdas:
SpringApplication.exit(ctx, () -> 0);
После вызова System.exit(ExitCode) программа завершается с кодом возврата 0 :
Process finished with exit code 0
5. Убейте процесс приложения
Наконец, мы также можем закрыть приложение Spring Boot из-за пределов приложения с помощью скрипта bash. Наш первый шаг для этой опции состоит в том, чтобы контекст приложения записал его PID в файл:
SpringApplicationBuilder app = new SpringApplicationBuilder(Application.class) .web(WebApplicationType.NONE); app.build().addListeners(new ApplicationPidFileWriter("./bin/shutdown.pid")); app.run();
Затем создайте файл shutdown.bat со следующим содержимым:
kill $(cat ./bin/shutdown.pid)
Выполнение shutdown.bat извлекает идентификатор процесса из файла shutdown.pid и использует команду kill для завершения загрузочного приложения.
6. Заключение
В этой быстрой записи мы рассмотрели несколько простых методов, которые можно использовать для завершения работы запущенного приложения Spring Boot.
Хотя выбор подходящего метода зависит от разработчика; все эти методы должны использоваться по замыслу и по назначению.
Например, .exit() предпочтительнее, когда нам нужно передать код ошибки в другую среду, скажем, JVM для дальнейших действий. Использование Приложения PID дает большую гибкость, так как мы также можем запустить или перезапустить приложение с помощью скрипта bash.
Наконец, /shutdown здесь, чтобы сделать возможным завершение работы приложений извне через HTTP . Для всех остальных случаев .close() будет работать отлично.
Как обычно, полный код этой статьи доступен в проекте GitHub .