Какие Spring Scope знаешь
В Spring Framework область видимости (scope) бина определяет, сколько экземпляров этого бина создаёт контейнер и как долго они живут. Основные встроенные области видимости: singleton (по умолчанию), prototype, request, session, application и websocket. Выбор правильного scope критичен для производительности, потокобезопасности и корректного управления состоянием в приложении.
Как это работает
Spring IoC-контейнер управляет жизненным циклом бинов в соответствии с их областью видимости. Для веб-областей (request, session, application, websocket) необходимо, чтобы приложение было веб-приложением (например, на основе Spring MVC или WebFlux). При использовании этих областей в не-веб-контексте или при внедрении в бины с большей областью видимости (например, singleton) требуется проксирование, чтобы обеспечить доступ к актуальному экземпляру в нужный момент.
Основные области видимости
Singleton
Область по умолчанию. Создаётся один экземпляр на весь контейнер Spring IoC. Все запросы возвращают один и тот же объект. Подходит для stateless-бинов и общих сервисов.
@Component
@Scope("singleton")
public class MySingletonBean {
}Prototype
Создаётся новый экземпляр при каждом запросе из контейнера. Полезно для stateful-бинов, когда каждый клиент должен иметь собственный экземпляр. Spring не управляет полным жизненным циклом prototype-бинов (не вызывает методы destroy).
@Component
@Scope("prototype")
public class MyPrototypeBean {
}Request
Один экземпляр на каждый HTTP-запрос. Уничтожается после завершения запроса. Используется для хранения данных, специфичных для запроса.
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyRequestBean {
}Session
Один экземпляр на пользовательскую сессию. Живёт, пока активна сессия. Подходит для хранения данных пользователя (например, корзины покупок).
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MySessionBean {
}Application
Один экземпляр на весь сервлет-контекст. Похож на singleton, но привязан к жизненному циклу веб-приложения. Используется для общих данных приложения.
@Component
@Scope(value = "application", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyApplicationBean {
}WebSocket
Один экземпляр на WebSocket-сессию. Позволяет хранить данные, специфичные для каждого WebSocket-соединения.
@Component
@Scope(value = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyWebSocketBean {
}Подводные камни
- Внедрение веб-скоупов в singleton: если внедрить request-бин в singleton, то при создании singleton будет зафиксирован один экземпляр request-бина. Чтобы этого избежать, используют
proxyMode = ScopedProxyMode.TARGET_CLASS(илиINTERFACES), который создаёт прокси, разрешающий актуальный бин при каждом обращении. - Prototype и уничтожение: контейнер не вызывает методы
@PreDestroyдля prototype-бинов, поэтому очистка ресурсов должна быть реализована вручную. - Производительность: singleton-бины быстрее, так как создаются один раз, но они должны быть потокобезопасными (не хранить изменяемое состояние). Prototype-бины создаются часто, что может быть затратно.
- Не-веб-контекст: области request, session, application, websocket недоступны в обычном standalone-приложении без веб-контекста.
Когда использовать
- Singleton — для сервисов, репозиториев, утилит без состояния.
- Prototype — для объектов с состоянием, которые не должны разделяться между потоками.
- Request — для данных одного HTTP-запроса (например, DTO, валидаторы).
- Session — для пользовательских данных, сохраняемых между запросами.
- Application — для глобальных настроек, кэшей.
- WebSocket — для данных, связанных с конкретным WebSocket-соединением.
Коротко
- Основные scope: singleton (по умолчанию), prototype, request, session, application, websocket.
- Singleton — один экземпляр на контейнер; prototype — новый при каждом запросе.
- Request, session, application, websocket — веб-области, требуют проксирования при внедрении в singleton.
- Выбор scope зависит от требуемого жизненного цикла и состояния бина.