Питання 11 · Розділ 5

Які scope існують в Spring?

4. Scoped Proxy — для впровадження вузьких scope в широкі 5. ObjectProvider — альтернатива Scoped Proxy 6. RefreshScope — для динамічної конфігурації

Мовні версії: English Russian Ukrainian

🟢 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

  1. Singleton — для сервісів і репозиторіїв
  2. Prototype — для важких stateful об’єктів
  3. Web scopes — для даних користувача
  4. Scoped Proxy — для впровадження вузьких scope в широкі
  5. ObjectProvider — альтернатива Scoped Proxy
  6. 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. Що таке proxy в Spring]]
  • [[14. Коли Spring створює proxy]]
  • [[16. Що таке аспект, advice, pointcut, join point]]