Spring Bean Scopes Nedir? Singleton, Prototype, Request, Session | Tam Rehber
Spring Bean Scopes — Eksiksiz Rehber
Spring IoC container'ı bir bean oluşturduğunda, o bean'in kaç kez ve ne zaman yaratılacağını scope (kapsam) belirler. Doğru scope seçimi hem bellek kullanımını optimize eder hem de kötü sürprizlerin — thread-safety sorunları, oturum sızıntıları, WebSocket veri karışıklıkları — önüne geçer. Bu yazıda altı scope'u örnekler, karşılaştırmalar ve pratik kullanım önerileriyle ele alıyoruz.
Hızlı özet
- Singleton — varsayılan; tüm uygulama için tek instance
- Prototype — her istemde yeni instance; stateful nesneler için
- Request / Session / Application / WebSocket — web uygulamalarına özel dört scope
- Scope,
@Scopeanotasyonu ya da XML ile belirlenir
1) Bean Scope Nedir?
Spring IoC container, uygulamanın omurgasını oluşturan nesneleri — bean'leri — yönetir. Bir bean tanımlandığında container şu soruyu sorar: "Bu nesneyi kaç kez oluşturayım ve yaşam döngüsü ne olsun?" İşte bu soruyu scope yanıtlar.
Spring, iki temel (core) ve dört web scope'u olmak üzere toplam altı yerleşik scope sunar. Bunlara ek olarak özel scope'lar da tanımlanabilir.
"Her bean'in doğru scope'u vardır. Yanlış seçim performans sorunlarına ya da gizli hatalara kapı açar."
2) Singleton Scope
Spring'in varsayılan scope'udur. Container başladığında bean bir kez oluşturulur ve uygulama boyunca aynı instance paylaşılır.
@Service
// @Scope("singleton") — anotasyon olmadan da aynı davranış
public class UserService {
// Tüm request'lerde paylaşılan tek instance
}
Ne zaman kullanılır?
State tutmayan (stateless) bileşenler için idealdir: @Service,
@Repository, @Controller. Bellekte tek kopya olduğu için
en verimli scope'tur.
Dikkat
Singleton bean'e mutable (değiştirilebilir) instance değişkeni eklenmemeli. Birden fazla thread aynı anda bu alanı değiştirebileceğinden thread-safety sorunu doğar.
3) Prototype Scope
Her bean isteminde (injection veya getBean() çağrısında)
yeni bir instance oluşturulur. Container, bu instance'ın
sonraki yaşam döngüsünü takip etmez; yönetim geliştiriciye kalır.
@Component
@Scope("prototype")
public class ShoppingCart {
private List<Item> items = new ArrayList<>();
public void addItem(Item item) { items.add(item); }
public List<Item> getItems() { return items; }
}
Not
Prototype bean'ler için Spring @PreDestroy metodunu
çağırmaz. Kaynakları serbest bırakmak uygulamanın sorumluluğundadır.
Singleton içinde Prototype kullanmak istiyorsanız
- Doğrudan inject ederseniz Prototype bean yalnızca bir kez oluşturulur — Singleton gibi davranır.
- Çözüm:
ApplicationContext.getBean()ile her seferinde manuel çekme. - Ya da
@Lookupanotasyonu ile Spring'in metodu override etmesini sağlama.
4) Web Scope'ları
Aşağıdaki dört scope yalnızca Spring web uygulamalarında (servlet-based) kullanılabilir. Her biri farklı bir "ömür" tanımlar.
ServletContext ile aynı yaşam döngüsüne sahiptir.
Uygulama genelinde paylaşılan konfigürasyon veya önbellek için kullanılır.
Web scope'ları için gereksinim
Request, Session, Application ve WebSocket scope'larını kullanabilmek için
Spring MVC'nin RequestContextListener ya da
RequestContextFilter'ın yapılandırılmış olması gerekir.
Spring Boot kullananlar için bu otomatik yapılır.
5) Tüm Scope'lar — Karşılaştırma Tablosu
| Scope | Kaç Instance? | Yaşam Süresi | Ne Zaman Kullanılır? |
|---|---|---|---|
| Singleton | Container başına 1 | Uygulama boyunca | Stateless servisler, repolar, controller'lar |
| Prototype | Her istemde yeni | Kullanıma bırakılmış | State tutan nesneler, her kullanımda izole instance gerektiğinde |
| Request | HTTP isteği başına 1 | İstek tamamlanınca | İstek bazlı veri işleme, form nesneleri |
| Session | Kullanıcı oturumu başına 1 | Oturum kapanınca | Kullanıcıya özgü veriler, alışveriş sepeti |
| Application | Web uygulaması başına 1 | Uygulama boyunca | Uygulama geneli paylaşılan veri, önbellek |
| WebSocket | WS bağlantısı başına 1 | Bağlantı kapanınca | Tek WebSocket bağlantısına özgü durum |
6) Scope Nasıl Tanımlanır?
@Scope anotasyonu ile
@Component
@Scope("prototype")
public class ReportGenerator { ... }
// Ya da sabit kullanarak (tavsiye edilir):
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ReportGenerator { ... }
Web scope'ları için
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION,
proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserPreferences {
private String theme = "light";
// ...
}
proxyMode neden gerekli?
Singleton bir bean, Session/Request scope'lu bir bean'i inject ettiğinde
container henüz o scope'u bilmiyor olabilir.
ScopedProxyMode.TARGET_CLASS ile Spring bir proxy oluşturur;
gerçek nesneye her erişimde doğru scope'tan alınır.
XML ile (klasik yaklaşım)
<bean id="userPreferences"
class="com.example.UserPreferences"
scope="session">
<aop:scoped-proxy/>
</bean>
7) Hangi Scope'u Seçmeliyim?
"Şüpheye düştüğünüzde Singleton ile başlayın. State ihtiyacı doğunca scope'u yükseltin."
8) Sık Yapılan Hatalar
Singleton + mutable field
Thread-safety sorunu yaratır. Singleton bean'e instance state eklemeyin; ya stateless yapın ya da ThreadLocal kullanın.
Singleton → Prototype inject
Prototype bean yalnızca bir kez oluşturulur ve Singleton gibi davranır. @Lookup veya ApplicationContext.getBean() tercih edin.
Session scope + proxy eksikliği
Singleton bir bean'e Session scope'lu bean inject ederken proxyMode belirtmeyi unutursanız uygulama context yüklenemez.
Application scope ≠ Singleton
Application scope ServletContext'e bağlıdır; Singleton scope Spring container'ına. Çoklu web uygulamasında farklı davranırlar.
9) Sık Sorulan Sorular
Spring'de varsayılan bean scope nedir?
Varsayılan scope Singleton'dır. @Scope belirtilmezse Spring, container başına tek bir instance oluşturur ve tüm bileşenlerle paylaşır.
Singleton ve Application scope farkı nedir?
Singleton, Spring IoC container başına tek instance anlamına gelir. Application scope ise ServletContext başına tek instance sağlar. Tek web uygulamasında pratikte aynı davransalar da çoklu context senaryolarında ayrışırlar.
Prototype bean'de @PreDestroy çalışır mı?
Hayır. Spring, Prototype bean'lerin yaşam döngüsünü oluşturma aşamasından sonra takip etmez. @PreDestroy çağrılmaz; kaynakları serbest bırakmak uygulamanın sorumluluğundadır.
Request scope'u non-web uygulamalarda kullanabilir miyim?
Hayır. Request, Session, Application ve WebSocket scope'ları yalnızca servlet tabanlı web uygulamalarında çalışır. Bir Spring Batch veya console uygulamasında bu scope'ları kullanmaya çalışırsanız hata alırsınız.
Özel (custom) scope tanımlanabilir mi?
Evet. org.springframework.beans.factory.config.Scope interface'i implement edip ConfigurableBeanFactory.registerScope() ile kaydederek tamamen özel bir scope oluşturabilirsiniz. Spring Cloud'un @RefreshScope'u bu mekanizmanın bilinen bir örneğidir.