Ответ
Нет, метод @PreDestroy не вызывается Spring-контейнером для бинов с областью видимости prototype.
Причина: Spring управляет полным жизненным циклом только для singleton бинов. Для бинов prototype контейнер отвечает только за их создание и инициализацию (вызов @PostConstruct), после чего передаёт экземпляр клиенту. Уничтожение prototype бина и освобождение его ресурсов — это ответственность клиентского кода.
Пример:
@Component
@Scope("prototype")
public class PrototypeBean {
@PostConstruct
public void init() {
System.out.println("Prototype bean initialized."); // Вызовется
}
@PreDestroy
public void cleanup() {
System.out.println("This will NOT be called by Spring!"); // Не вызовется
}
}
Альтернативы для освобождения ресурсов:
- Реализовать интерфейс
DisposableBean(не рекомендуется из-за связывания с Spring API). - Использовать кастомный метод уничтожения в
@Beanопределении:@Bean(destroyMethod="myCleanup"). - Вызывать метод очистки явно в клиентском коде, когда работа с бином завершена.
- Использовать шаблон «callback»: определить собственный интерфейс очистки, который клиент будет вызывать.
Ответ 18+ 🔞
Да ты посмотри, какая дичь, блядь! Вот сидишь ты, такой весь в себе, думаешь: «А, Spring, блядь, умный фреймворк, всё за меня сделает, вызовет, почистит, в рот меня чих-пых!». Ан хуй там, а не везде!
Смотри сюда, распиздяй. Берёшь ты бин, накручиваешь на него @Scope("prototype"). Ну, чтобы он каждый раз новый, как девственница, блядь, свежий и незаезженный. И пишешь ты ему два метода: один @PostConstruct — чтобы инициализировался, красавчик, а второй @PostDestroy — чтобы, значит, на выходе прибрался, как порядочный.
И что же выходит? А выходит пиздец, вот что! Spring, этот хитрожопый контейнер, для prototype бина делает только полдела. Он его родит, вызовет @PostConstruct (тут всё честно), и — хуяк! — суёт тебе в руки, мол, «на, распидорасил, дальше сам разбирайся». А про то, чтобы его убить и @PreDestroy вызвать, он нихуя не думает! Совсем! Ответственность, блядь, перекладывает.
Вот смотри на код, небось думал, что всё сработает:
@Component
@Scope("prototype")
public class PrototypeBean {
@PostConstruct
public void init() {
System.out.println("Prototype bean initialized."); // О, это да, это он позовёт!
}
@PreDestroy
public void cleanup() {
System.out.println("This will NOT be called by Spring!"); // А вот это — нет, сука! Никогда!
}
}
Вот и сиди теперь с этим prototype бином, как дурак. Он тебе память жрёт, ресурсы держит, а Spring только плечами пожимает: «Не моя, мол, зона, чувак. Я свою работу сделал — создал».
Ну и что делать-то, спрашивается? Сидеть и плакать? Да нет же, ёпта! Есть же варианты, хоть и кривожопые:
DisposableBean— интерфейс этот старый, дедовский. Реализуешь его, переопределяешьdestroy(). Но это ж связывание с API Spring, блядь! Не комильфо.- Кастомный
destroyMethodв@Bean— если объявляешь бин через Java-конфиг, можно ткнуть пальцем:@Bean(destroyMethod="myCleanup"). Скажешь ему, мол, вот этот метод, блядь, дергай на уничтожение. Но опять же, дляprototype— хер ты чего добьёшься, если контейнер им не управляет. - Сам, блядь, вызови! — Вот самый честный путь. Когда клиентский код заканчивает с этим бином работать, он должен явно, как мужчина, позвать метод очистки. Типа
prototypeBean.cleanup(). Ответственность, сука, на тебе. - Шаблон «колбэк» — Сделаешь свой интерфейсик,
Cleanableтам какой-нибудь. Бин его реализует, а клиент, когда надо, дергаетclean(). Красиво, но мороки — овердохуища.
Короче, вывод простой, как три рубля: prototype бин — это как гость в твоей квартире. Spring его только в дверь запустит (@PostConstruct), а выпроваживать (@PreDestroy) — это уже твоя, блядь, головная боль. Не забывай об этом, а то ресурсы по углам протекать начнут!