Управляет ли Spring полным жизненным циклом бина с областью видимости prototype?

Ответ

Нет, Spring не управляет полным жизненным циклом prototype-бина. Управление ограничивается фазами создания и настройки.

Жизненный цикл prototype-бина в Spring:

  1. Создание (Instantiation): Новый экземпляр создается при каждом запросе (через ApplicationContext.getBean() или инъекцию зависимости).
  2. Настройка (Population & Initialization): Spring внедряет зависимости и вызывает метод, помеченный аннотацией @PostConstruct.
  3. Уничтожение (Destruction): Spring НЕ вызывает метод @PreDestroy для prototype-бинов. Очистка ресурсов (закрытие соединений, файлов) и удаление из памяти — ответственность клиентского кода и JVM (сборщика мусора).

Почему так? Область prototype подразумевает, что Spring возвращает управление объектом клиенту сразу после его создания и настройки. Контейнер не отслеживает дальнейшую судьбу этих экземпляров.

Пример:

@Component
@Scope("prototype")
public class PrototypeService {
    @PostConstruct
    public void init() {
        System.out.println("Prototype bean created and initialized.");
    }
    @PreDestroy
    public void cleanup() {
        // ЭТОТ МЕТОД НИКОГДА НЕ ВЫЗОВЕТСЯ SPRING'OM!
        System.out.println("Это сообщение не появится.");
    }
}

Для корректного освобождения ресурсов prototype-бинов необходимо использовать шаблоны вроде DisposableBean с явным вызовом метода уничтожения в клиентском коде.

Ответ 18+ 🔞

А, слушай, вот тут народ частенько путается, как с тем Герасимом из «Муму» — думает, раз Spring такой всемогущий, то он за всё отвечает, даже за прототипы. Ан хуй там плавал!

Вот смотри, чтобы не быть как тот немой крестьянин, который только «Му-му» мычит, давай разжую.

Spring для prototype-бина — это как мамка, которая родила, покормила, в школу первый раз отвела и говорит: «Всё, сынок, дальше сам, блядь!». Управление полным циклом? Да ни хуя подобного! Контейнер только две фазы делает:

  1. Создание (Instantiation): Каждый раз, когда ты просишь бина (через getBean() или инъекцию), Spring, как заведённый, лепит новый экземпляр. Овердохуища копий может наделать.
  2. Настройка (Population & Initialization): Впендюрит ему все зависимости, какие надо, и вызовет метод с @PostConstruct. Типа, «на, сынок, портфель собран и бутерброд дал».

А дальше — всё, пипец, отвязка! Фаза уничтожения? Spring про неё для прототипов слышать не хочет. Метод @PreDestroy — это как та самая Муму для Герасима: он его в принципе видит, но вызвать — ни боже мой, не его собака, пусть клиентский код сам разбирается.

Почему так, ёпта? А потому что логика prototype — это «сделал и забыл». Контейнер выдал тебе объект, и с этого момента ты за него в ответе. Он не будет, как дурак, бегать за каждым экземпляром и следить, не пора ли его в утиль. Это ж пиздец какой overhead был бы!

Пример, чтобы вообще всё стало ясно:

@Component
@Scope("prototype")
public class PrototypeService {
    @PostConstruct
    public void init() {
        System.out.println("Prototype bean создан и проинициализирован. Жизнь удалась!");
    }
    @PreDestroy
    public void cleanup() {
        // ЭТОТ МЕТОД НИКОГДА НЕ ВЫЗОВЕТСЯ SPRING'OM, ЯДРЁНА ВОШЬ!
        // Это сообщение — несбыточная мечта, как мир во всём мире.
        System.out.println("Это сообщение не появится. Вообще.");
    }
}

Вот и получается, что если твой прототипный бин держит какие-то ресурсы (соединения, файлы), то Spring про них благополучно забьёт хуй. Закрывать их — это твоя головная боль, чувак. Придётся либо шаблоны проектирования использовать, либо вручную вызывать метод очистки. А то так и до утечек памяти недалеко, а потом сиди и думай: «И кто ж тут серит на крыше?».