В чем минусы scope prototype в Spring
Что проверяют
Понимаете ли вы, как контейнер обращается с бинами разных скоупов, и знаете ли классическую ловушку с внедрением prototype в singleton. Следом почти всегда просят показать, как правильно получать новый экземпляр при каждом обращении.
Как отвечать
Бин со скоупом prototype (@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)) создаётся заново при каждом запросе к контейнеру: при getBean() или при внедрении в другой бин. Минусы вытекают из этого:
- неполный жизненный цикл: Spring создаёт бин, внедряет зависимости, вызывает
@PostConstructи отдаёт объект.@PreDestroyиDisposableBean.destroy()для prototype не вызываются, соединения, потоки и файлы закрывать приходится самим; - ловушка с singleton: внедрение происходит один раз, при создании singleton. Сервис получит один экземпляр prototype и будет держать его всю жизнь, то есть фактически тот же singleton;
- стоимость создания: каждый раз работают рефлексия, все
BeanPostProcessorи, если есть аспекты, создание прокси. На горячем пути это заметно; - поздние ошибки: prototype не создаётся при старте контекста, поэтому ошибка конфигурации всплывёт при первом обращении, а не при запуске;
- циклические зависимости между prototype-бинами контейнер не разрешает, будет
BeanCurrentlyInCreationException.
Свежий экземпляр внутри singleton получают так:
ObjectProvider<T>иgetObject(), основной способ;jakarta.inject.Provider<T>;- метод с аннотацией
@Lookup, который Spring переопределит сам; - прокси через
proxyMode = ScopedProxyMode.TARGET_CLASS, но с оговоркой ниже.
Где спотыкаются
Думают, что prototype нельзя внедрить в singleton. Можно, просто экземпляр будет один на всё время жизни сервиса.
Ставят scoped proxy на prototype и не понимают поведения: новый экземпляр создаётся на каждый вызов метода через прокси, и состояние между двумя вызовами теряется.
Говорят про утечки памяти из-за prototype. Сами объекты соберёт GC, как только на них не останется ссылок. Утекают ресурсы, которые бин держит и которые никто не закрыл, потому что destroy-методы не вызываются.