Spring: Жизненный цикл бинов, методы init() и destroy()
Всем привет! Я начинающий Java-разработчик. В рамках развития своей карьеры я решил сделать две вещи:
- Завести канал в ТГ, где собираюсь рассказывать о себе, своем пути и проблемах, с которыми сталкиваюсь — https://t.me/java_wine
- Завести блог на Хабре, куда буду выкладывать переводы материалов, которые использую для своего обучения и развития.
Надеюсь, буду полезен сообществу и новичкам, которые пойдут по моим или чьим-то еще стопам.
Жизненный цикл любого объекта означает следующее: как и когда он появляется, как он себя ведет во время жизни и как и когда он исчезает. Жизненный цикл бина ровно про это же: «как и когда».
Жизненным циклом управляет спринг-контейнер. В первую очередь после запуска приложения запускается именно он. После этого контейнер по необходимости и в соответствии с запросами создает экземпляры бинов и внедряет необходимые зависимости. И, наконец, бины, связанные с контейнером, уничтожаются когда контейнер завершает свою работу. Поэтому, если мы хотим выполнить какой-то код во время инстанцирования бина или сразу после завершения работы контейнера, один из самых доступных нам вариантов это вынести его в специальные init() и destroy() методы.
На картинке условно это можно изобразить следующим образом
Спринг предоставляет несколько способ настроить выполнение этих методов. Для того чтобы понять и разобраться в них, давайте посмотрим на простой пример.
Попробуем создать бин HelloWorld и вызвать у него методы init() и destroy(). Сделаем это тремя разными способами:
XML
Сначала сделаем простой класс:
public class HelloWorld < public void init() throws Exception < System.out.println("Я инит-метод " + this.getClass().getSimpleName()); >public void destroy() throws Exception < System.out.println("Я дестрой-метод " + this.getClass().getSimpleName()); >>
Чтобы использовать пользовательские методы init() и destroy() нам необходимо зарегистрировать их в Spring XML конфигурационном файле при описании бина:
Также потребуется класс-runner, который и запустит наш контекст:
Обратите внимание, что в нём указан адрес файла конфигурации бинов.
Java-код («программный метод»)
Для того чтобы это реализовать необходимо в классе бина HelloWorldByJavaCode имплементировать два интерфейса, InitializingBean и DisposableBean, а затем переопределить методы afterPropertiesSet() и destroy().
Метод afterPropertiesSet() вызывается при запуске спринг-конейтнера и инстанцировании бина, а метод destroy() сразу после того как контейнер завершит свою работу.
Чтобы вызвать метод destroy() нам необходимо явно закрыть спринг-контекст, вызвав метод close() у объекта ConfigurableApplicationContext.
public class HelloWorldByJavaCode implements InitializingBean, DisposableBean < @Override public void destroy() throws Exception < System.out.println("Я дестрой-метод " + this.getClass().getSimpleName()); >@Override public void afterPropertiesSet() throws Exception < System.out.println("Я инит-метод " + this.getClass().getSimpleName()); >>
В XML регистрация бина будет выглядеть так:
Класс-runner остается прежним
С помощью аннотаций
Чтобы вызывать методы init() и destroy() нам необходимо указать над методами соответствующие аннотации — @PostConstruct и @PreDestroy.
Чтобы вызвать метод destroy() нам необходимо явно закрыть спринг-контекст, вызвав метод close() у объекта ConfigurableApplicationContext. Класс-runner остается прежним
Cоздадим бин HelloWorldByAnnotations.java и аннотируем соответствующие методы:
public class HelloWorldByAnnotations < @PostConstruct public void init() throws Exception < System.out.println("Я инит-метод " + this.getClass().getSimpleName()); >@PreDestroy public void destroy() throws Exception < System.out.println("Я дестрой-метод " + this.getClass().getSimpleName()); >>
В XML-файле появится дополнительная строчка, отвечающая за бин, читающий аннотации:
Размещу еще одну схему жизненного цикла, более полную. Взял её уже с другого ресурса. Мне кажется для понимания и подготовки к собеседованиям полезно.