Какие области видимости (scopes) есть у Spring Bean кроме singleton и prototype
Что проверяют
Знаете ли вы веб-области и, главное, как бин с коротким жизненным циклом живёт внутри синглтона. Уточнение почти всегда одно: что будет, если внедрить request-бин в обычный сервис.
Как отвечать
Эти области работают только в веб-контексте, например в Spring MVC:
- request: экземпляр на HTTP-запрос, аннотация
@RequestScope. Подходит для данных текущего запроса: идентификатор трассировки, контекст пользователя; - session: экземпляр на HTTP-сессию,
@SessionScope. Если сессии реплицируются или хранятся в Spring Session с Redis, бин должен бытьSerializable; - application: экземпляр на
ServletContext,@ApplicationScope. Синглтон живёт в пределах одногоApplicationContext, а application-бин лежит атрибутомServletContextи общий для всех контекстов веб-приложения; - websocket: экземпляр на WebSocket-сессию, используется вместе с обменом сообщениями по STOMP.
globalSession для портлетов удалён в Spring 5 вместе с поддержкой портлетов, называть его актуальным не стоит.
Дальше главный механизм. Синглтон создаётся один раз, и напрямую внедрить в него request-бин нельзя. Нужен прокси: @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS), а у @RequestScope и @SessionScope такой режим включён по умолчанию. Прокси при каждом вызове находит настоящий бин текущего запроса. Вариант без прокси: ObjectProvider<T> и вызов getObject() в нужный момент.
Плюсом будут кастомные области: интерфейс Scope и ConfigurableBeanFactory.registerScope(). Готовые примеры: SimpleThreadScope (есть в Spring, но не зарегистрирован по умолчанию), @RefreshScope из Spring Cloud, @StepScope и @JobScope из Spring Batch.
Где спотыкаются
Обращаются к request-бину вне потока запроса, из @Async или планировщика, и получают IllegalStateException о том, что к потоку не привязан запрос.
Кладут в session-бин тяжёлые объекты или ссылки на сервисы. Сессия перестаёт сериализоваться, а память растёт с числом пользователей.
Говорят, что application и singleton «одно и то же». В Spring Boot с одним контекстом разница незаметна, но механизм и место хранения у них разные.