Какие существуют скоупы Spring Bean?
Что проверяют
Знаете ли вы актуальный список скоупов и, главное, что происходит, когда бины разных скоупов внедряются друг в друга. Классический следующий вопрос: «prototype внедрён в singleton, сколько будет экземпляров».
Как отвечать
Сначала перечислите скоупы:
singleton: по умолчанию. Один экземпляр наApplicationContext, а не на JVM, как у паттерна Singleton. Создаётся при старте контекста, если не помечен@Lazy;prototype: новый экземпляр на каждыйgetBean()или внедрение. Контейнер создаёт и настраивает бин, но не управляет его уничтожением,@PreDestroyне вызывается;request: экземпляр на HTTP-запрос;session: экземпляр на HTTP-сессию;application: один наServletContext, похож на singleton, но общий для нескольких контекстов в одном веб-приложении;websocket: на время WebSocket-сессии.
Последние четыре работают только в веб-контексте. Свой скоуп регистрируется через интерфейс Scope и CustomScopeConfigurer: так устроены SimpleThreadScope (есть в Spring, но не включён по умолчанию) и @RefreshScope в Spring Cloud.
Теперь проблема короткоживущих бинов внутри долгоживущих. Prototype, внедрённый в singleton, создаётся один раз вместе с singleton, и дальше это всегда тот же объект. Решения:
ObjectProvider<T>:getObject()возвращает новый экземпляр при каждом вызове;@Lookup: метод, который Spring переопределяет и отдаёт бин из контекста;- scoped proxy:
proxyMode = ScopedProxyMode.TARGET_CLASS. У@RequestScopeи@SessionScopeпрокси включён по умолчанию, поэтому их можно внедрять в singleton-сервисы.
Где спотыкаются
Называют globalSession. Он существовал для портлетов и ушёл вместе с их поддержкой в Spring 5.
Считают singleton потокобезопасным. Контейнер гарантирует один экземпляр, но не синхронизацию, и изменяемое поле в сервисе даёт гонку между запросами.
Ждут вызова @PreDestroy у prototype-бина и держат в нём ресурсы, которые никто не закроет.