Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

Документы

Медиа

Назад
Вопрос про Spring: Spring, @PreDestroy, prototype bean, lifecycle, dependency injection

Работает ли @PreDestroy для prototype-бинов?

Этот вопрос проверяет понимание жизненного цикла prototype-бинов в Spring и различий в управлении их уничтожением по сравнению с singleton-бинами.

Короткий ответ

Нет, аннотация @PreDestroy не работает для prototype-бинов в Spring Framework. Spring полностью управляет жизненным циклом singleton-бинов, включая их уничтожение при закрытии контекста, поэтому для них вызываются методы с @PreDestroy. Однако для prototype-бинов Spring создаёт новый экземпляр при каждом запросе, но не отслеживает их после создания и внедрения зависимостей. Ответственность за освобождение ресурсов prototype-бина лежит на клиентском коде, который его использует.

Длинный ответ

В Spring Framework аннотация @PreDestroy используется для пометки метода, который должен быть выполнен перед уничтожением бина. Это часть механизма обратных вызовов жизненного цикла, аналогичного @PostConstruct для инициализации. Однако её поведение кардинально отличается для бинов с разной областью видимости (scope).

Различия между Singleton и Prototype бинами

Spring контейнер управляет полным жизненным циклом singleton-бинов (область видимости по умолчанию). Контейнер создаёт один экземпляр, хранит его и вызывает методы с аннотациями @PostConstruct и @PreDestroy в соответствующие моменты. При закрытии контекста (например, при остановке приложения) Spring гарантированно вызовет @PreDestroy для всех singleton-бинов, чтобы освободить ресурсы (закрыть соединения с БД, файлы и т.д.).

Для prototype-бинов (область видимости @Scope("prototype")) Spring действует иначе. Контейнер создаёт новый экземпляр бина каждый раз, когда он запрашивается через getBean() или внедряется как зависимость. После создания и внедрения зависимостей (и вызова @PostConstruct, если он есть) Spring передаёт управление объектом клиентскому коду и больше не отслеживает его. Контейнер не знает, когда клиент закончит использовать этот объект, поэтому не может автоматически вызвать метод уничтожения.

Почему @PreDestroy не вызывается

  • Spring не хранит ссылки на созданные prototype-бины, чтобы избежать утечек памяти.
  • Уничтожение prototype-бина зависит от логики приложения: объект может быть использован кратковременно или передан в долгоживущий кэш.
  • Ответственность за освобождение ресурсов (вызов close(), shutdown() и т.п.) перекладывается на клиентский код, который создал или получил бин.

Пример кода и альтернативы

Рассмотрим простой пример, демонстрирующий проблему:

@Component
@Scope("prototype")
public class PrototypeResource {
    private FileInputStream fileStream;
    
    @PostConstruct
    public void init() {
        System.out.println("Prototype bean created");
        // Открываем ресурс
        fileStream = new FileInputStream("data.txt");
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("Этот метод НЕ будет вызван для prototype!");
        // Потенциальная утечка ресурса
        // fileStream.close();
    }
    
    // Явный метод для ручного освобождения ресурсов
    public void manualCleanup() throws IOException {
        if (fileStream != null) {
            fileStream.close();
            System.out.println("Ресурс освобождён вручную");
        }
    }
}

Чтобы правильно работать с ресурсами в prototype-бинах, используйте следующие подходы:

  1. Шаблон «Disposable»: Реализуйте интерфейс DisposableBean или добавьте собственный метод (например, destroy()), который клиент должен вызывать явно.
  2. Использование try-with-resources (для Java): Если бин реализует AutoCloseable, клиент может использовать его в блоке try-with-resources.
  3. Переход на singleton с пулом ресурсов: Если требуется многократное создание объектов с тяжёлыми ресурсами, рассмотрите использование пулов (например, пул соединений с БД).
  4. Создание фабрики с явным управлением жизненным циклом: Фабричный метод может возвращать экземпляры и предоставлять отдельный метод для их очистки.

Вывод: Аннотацию @PreDestroy не следует использовать для prototype-бинов, так как Spring её игнорирует. Для освобождения ресурсов prototype-бинов необходимо применять явные методы очистки, вызываемые клиентским кодом, или пересмотреть архитектуру, чтобы использовать singleton-бины с правильным управлением состоянием.

Уровень

  • Рейтинг:

    3

  • Сложность:

    5

Навыки

  • Spring

    Spring

Ключевые слова

#Spring

#@PreDestroy

#prototype bean

#lifecycle

#dependency injection

Подпишись на Java Developer в телеграм