Как получить событие уничтожения бина в Spring
JavaSpringлогированиесобытияуправление жизненным циклом
Что проверяют
Знаете ли вы способы освободить ресурсы при остановке приложения и понимаете ли, для каких бинов это вообще не сработает.
Как отвечать
Три способа, от предпочтительного:
@PreDestroyна методе бина. Стандартная аннотация, вызывается перед уничтожением;- параметр
destroyMethodу@Bean: удобно для чужих классов, которые нельзя аннотировать. Для объектов с методомcloseон подставляется автоматически, потому что значение по умолчанию это определение метода закрытия; - интерфейс
DisposableBeanс методомdestroy. Работает, но привязывает класс к Spring, поэтому используется реже.
Что обязательно проговорить:
- для бинов с областью
prototypeэти методы не вызываются вообще. Контейнер создаёт такой объект и забывает о нём, освобождение остаётся на вызывающем. Это самая частая ловушка вопроса; - порядок: бины уничтожаются в порядке, обратном созданию, поэтому зависимости ещё живы в момент вызова;
- приложение должно корректно завершаться: в Spring Boot перехват сигнала завершения включён по умолчанию, а при ручном создании контекста нужен
registerShutdownHook. Убийство процесса сигналом остановки без ожидания не даст методам выполниться; - плавная остановка веб-сервера настраивается отдельно (
server.shutdown=graceful), чтобы дать текущим запросам завершиться; - события контекста:
ContextClosedEventчерез слушателя, если нужно узнать об остановке приложения целиком, а не отдельного бина.
Где спотыкаются
Ждут вызова метода уничтожения у бина с областью prototype.
Освобождают ресурсы только в методе уничтожения, забывая, что при аварийном завершении процесса он не выполнится.
Делают в методе долгую работу и упираются в таймаут остановки, из-за чего часть операций обрывается.