Какие scope существуют в Spring?
4. Scoped Proxy — для внедрения узких scope в широкие 5. ObjectProvider — альтернатива Scoped Proxy 6. RefreshScope — для динамической конфигурации
🟢 Junior Level
Scope определяет, сколько экземпляров бина создаёт Spring.
| Scope | Сколько экземпляров |
|---|---|
| Singleton | Один на всё приложение (по умолчанию) |
| Prototype | Новый при каждом запросе |
| Request | Один на HTTP запрос |
| Session | Один на HTTP сессию |
@Service // Singleton
public class UserService { }
@Scope("prototype")
@Service
public class Report { } // Новый каждый раз
🟡 Middle Level
Standard Scopes
Singleton:
// Один экземпляр на ApplicationContext
// Все потоки используют один объект
// → Должен быть Stateless!
Prototype:
// Новый при каждом getBean()
// Spring НЕ вызывает @PreDestroy!
// → Вы сами чистите ресурсы
Web Scopes
@Scope("request") // Один на HTTP запрос
@Scope("session") // Один на сессию пользователя
@Scope("application") // Один на ServletContext
Custom Scopes
// Свой scope!
context.getBeanFactory().registerScope("thread", new ThreadScope());
// ThreadScope — кастомная реализация интерфейса org.springframework.beans.factory.config.Scope.
// Хранит бины в ThreadLocal. В стандартном Spring такой scope не встроен — это пример.
// Spring Cloud: Refresh Scope
// → Бин пересоздаётся при обновлении конфигурации
Проблема: узкий scope в Singleton
// ❌ Request бин создастся один раз при старте Singleton
@Service
public class SingletonService {
@Autowired RequestBean requestBean; // Застрял первый!
}
// ✅ Scoped Proxy
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Bean public RequestBean requestBean() { }
// ✅ ObjectProvider
@Autowired ObjectProvider<RequestBean> provider;
RequestBean bean = provider.getObject(); // Актуальный!
🔴 Senior Level
ScopedProxyMode
TARGET_CLASS (CGLIB):
→ Создаёт прокси-наследник
→ Прокси → RequestContextHolder → актуальный бин
INTERFACES (JDK):
→ Проксирует только интерфейсы
NO:
→ Без прокси → проблема с Singleton
Under the hood: где хранятся
Singleton → DefaultSingletonBeanRegistry (ConcurrentHashMap)
Request → хранится в атрибутах HttpServletRequest, доступ через RequestContextHolder (ThreadLocal)
Session → SessionAttributes
Prototype → Не хранится, создаётся каждый раз
Refresh Scope (Spring Cloud)
@RefreshScope
@ConfigurationProperties("my.config")
public class MyConfig { }
// При обновлении через Spring Cloud Bus:
// → Прокси инвалидируется
// → При следующем запросе создаётся заново с новыми данными
Production Experience
Реальный сценарий: Session scope в микросервисе
Session scope → ThreadLocal → работает на одной ноде
→ Load Balancer → запрос на другую ноду → Session потерялся!
Решение: Spring Session + Redis
→ Session хранится в Redis → доступен на всех нодах
Best Practices
- Singleton — для сервисов и репозиториев
- Prototype — для тяжёлых stateful объектов
- Web scopes — для данных пользователя
- Scoped Proxy — для внедрения узких scope в широкие
- ObjectProvider — альтернатива Scoped Proxy
- RefreshScope — для динамической конфигурации
Резюме для Senior
- Singleton = один на ApplicationContext
- Prototype = новый каждый раз, @PreDestroy НЕ работает
- Request/Session = web scope через ThreadLocal
- Scoped Proxy = прокси → RequestContextHolder
- RefreshScope = пересоздание при обновлении конфига
- Custom Scope = свой lifecycle
🎯 Шпаргалка для интервью
Обязательно знать:
- 4 стандартных scope: Singleton (по умолчанию), Prototype, Request, Session
- Singleton = один экземпляр на ApplicationContext, Prototype = новый при каждом запросе
- Web scope (Request/Session) хранятся через ThreadLocal
- ScopedProxyMode (TARGET_CLASS/CGLIB, INTERFACES/JDK, NO) решает проблему внедрения узких scope в широкие
- @PreDestroy НЕ вызывается для Prototype — ресурсы чистите вручную
- ObjectProvider — альтернатива Scoped Proxy для Prototype/Request в Singleton
- RefreshScope (Spring Cloud) — пересоздание бина при обновлении конфигурации
Частые уточняющие вопросы:
- Как внедрить Request scope в Singleton? → Scoped Proxy (
proxyMode = TARGET_CLASS) или ObjectProvider - Что произойдёт, если Prototype бин содержит ресурсы? → Утечка, Spring не вызовет @PreDestroy, нужно чистить вручную через try-finally
- Где Spring хранит Singleton бины? → DefaultSingletonBeanRegistry (ConcurrentHashMap)
- Что делает RefreshScope? → Инвалидирует прокси, при следующем запросе создаёт бин заново с новыми данными
Красные флаги (НЕ говорить):
- «Prototype вызывает @PreDestroy» — не вызывает
- «Request scope хранится в кэше Spring» — хранится в атрибутах HttpServletRequest
- «Singleton создаётся при каждом обращении» — создаётся один раз
- «Custom Scope встроен в Spring» — нужно писать свою реализацию интерфейса Scope
Связанные темы:
- [[12. В чём разница между singleton и prototype scope]]
- [[13. Что такое прокси в Spring]]
- [[14. Когда Spring создаёт прокси]]
- [[16. Что такое аспект, advice, pointcut, join point]]