Почему Spring контейнер не вызывает метод destroy для бинов со scope=»prototype»?

«Почему Spring контейнер не вызывает метод destroy для бинов со scope=»prototype»?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Spring контейнер управляет полным жизненным циклом только для синглтон-бинов. Для бинов со scope="prototype" контейнер выполняет только инициализацию (вызывает методы @PostConstruct, InitializingBean.afterPropertiesSet()), а затем передаёт экземпляр клиенту.

Причина: Контейнер не отслеживает дальнейшую судьбу prototype-бинов, так как их может быть создано множество, и момент их окончания использования неизвестен. Поэтому финализация (@PreDestroy, DisposableBean.destroy()) не вызывается автоматически.

Решение для очистки ресурсов: Клиентский код, получивший prototype-бин, должен явно вызвать метод очистки, когда бин больше не нужен. Можно использовать ConfigurableBeanFactory.destroyBean().

Пример:

@Scope("prototype")
@Component
public class ExpensiveResourceBean implements DisposableBean {
    @Override
    public void destroy() {
        System.out.println("Освобождение ресурсов prototype-бина");
    }
}

@Service
public class ClientService {
    @Autowired
    private ConfigurableBeanFactory beanFactory;

    public void process() {
        // Контейнер создает и инициализирует новый бин
        ExpensiveResourceBean bean = beanFactory.getBean(ExpensiveResourceBean.class);
        try {
            // Использование бина
        } finally {
            // Явный вызов уничтожения для очистки
            beanFactory.destroyBean(bean);
        }
    }
}