Woche 2, Tag 4 — Bean Scopes: singleton, prototype, request, session und scoped proxy
Ziel
Heute verstehst du Spring Bean Scopes.
Die Kernfragen:
- Was ist ein Bean Scope?
- Was ist der Default Bean Scope?
- Was bedeutet singleton in Spring?
- Ist Spring singleton dasselbe wie das Java-Singleton-Pattern?
- Was ist prototype Scope?
- Was ist request Scope?
- Was ist session Scope?
- Was passiert, wenn ein prototype Bean in einen singleton Bean injiziert wird?
- Was ist
ObjectProvider? - Was ist ein scoped proxy?
- Welche typischen Prüfungsfallen gibt es?
1. Kurz-Wiederholung von Tag 3
An Tag 3 hast du gelernt:
- Profiles steuern, welche Configuration und welche Beans aktiv sind.
application-dev.ymllädt nur, wenndevaktiv ist.@Profile("dev")heißt: Die Bean ist nur imdev-Profile aktiv.@Profile("!prod")heißt: Die Bean ist aktiv, wennprodnicht aktiv ist.- Mehrere Profiles können gleichzeitig aktiv sein.
- Profiles sind für Unterschiede auf Umgebungsebene.
Merksatz:
Profiles steuern, welche Beans und welche Configuration aktiv sind.
Heute lernst du Bean Scopes.
2. Was ist ein Bean Scope?
Ein Bean Scope definiert:
Wie lange ein Spring Bean lebt und wie viele Instanzen Spring erzeugt.
Einfache Fragen, die ein Scope beantwortet:
Erzeugt Spring ein Objekt?
Erzeugt Spring jedes Mal ein neues Objekt?
Erzeugt Spring ein Objekt pro HTTP-Request?
Erzeugt Spring ein Objekt pro HTTP-Session?
Kurze Definition:
Ein Bean Scope steuert den Lifecycle und die Sichtbarkeit einer Spring-Bean-Instanz.
3. Häufige Spring Bean Scopes
Häufige Scopes:
| Scope | Bedeutung |
|---|---|
singleton | eine Bean-Instanz pro Spring container |
prototype | neue Bean-Instanz bei jeder Anfrage |
request | eine Bean-Instanz pro HTTP-Request |
session | eine Bean-Instanz pro HTTP-Session |
application | eine Bean-Instanz pro ServletContext |
websocket | eine Bean-Instanz pro WebSocket-Session |
Für die Prüfung am wichtigsten:
singleton
prototype
request
session
4. Default Bean Scope
Der Default Spring Bean Scope ist:
singleton
Beispiel:
@Service
public class OrderService {
}
Das ist standardmäßig ein singleton Bean.
Spring erzeugt eine OrderService-Instanz pro Spring container.
Merksatz:
Der Default Bean Scope in Spring ist singleton.
5. Was bedeutet singleton in Spring?
Spring singleton bedeutet:
Eine Bean-Instanz pro Spring IoC container.
Beispiel:
@Service
public class OrderService {
}
Spring erzeugt eine Instanz:
ApplicationContext
└── orderService -> ein OrderService-Objekt
Wenn drei Controller OrderService injizieren, bekommen sie alle dieselbe Bean-Instanz.
6. Spring-Singleton-Beispiel
@Service
public class OrderService {
}
@RestController
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
}
@RestController
public class AdminOrderController {
private final OrderService orderService;
public AdminOrderController(OrderService orderService) {
this.orderService = orderService;
}
}
Beide Controller bekommen dieselbe OrderService-Instanz.
OrderController -> dieselbe OrderService Bean
AdminOrderController -> dieselbe OrderService Bean
7. Spring singleton vs. Java-Singleton-Pattern
Das ist eine wichtige Prüfungsfalle.
Spring singleton
Eine Bean-Instanz pro Spring container.
Java-Singleton-Pattern
Meist eine Instanz pro JVM, gesteuert über statischen Zugriff.
Java-Singleton-Beispiel:
public class AppConfig {
private static final AppConfig INSTANCE = new AppConfig();
private AppConfig() {
}
public static AppConfig getInstance() {
return INSTANCE;
}
}
Spring singleton ist nicht dasselbe.
Merksatz für die Prüfung:
Spring singleton bedeutet eine Bean-Instanz pro Spring container — nicht eine Instanz pro JVM.
8. Kann es mehr als eine Spring-Singleton-Instanz geben?
Ja.
Gibt es mehrere Spring container, kann jeder container seinen eigenen singleton Bean haben.
Beispiel:
ApplicationContext 1 -> ein OrderService
ApplicationContext 2 -> ein OrderService
Spring singleton ist also container-spezifisch.
9. Singleton-Beans musst du sorgfältig designen
Weil singleton Beans geteilt werden, sollten sie meist stateless sein.
Guter singleton Service:
@Service
public class PriceCalculator {
public BigDecimal calculatePrice(Order order) {
return order.items().stream()
.map(Item::price)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
Das ist gut, weil die Methode lokale Variablen und Eingabeparameter nutzt.
10. Schlechter Singleton-Bean mit mutable State
Schlecht:
@Service
public class OrderService {
private Long currentOrderId;
public void process(Long orderId) {
this.currentOrderId = orderId;
// business logic
}
}
Problem:
OrderService wird von vielen Requests geteilt.
currentOrderId kann von einem anderen Request überschrieben werden.
Das kann Race Conditions und falsche Daten verursachen.
Singleton Services sollten keinen request-spezifischen State in Feldern speichern.
11. Gute Regel für Singleton
Gut:
@Service
public class OrderService {
public void process(Long orderId) {
Long currentOrderId = orderId;
// use local variable
}
}
Merksatz:
Singleton Beans sollten meist stateless sein.
12. Ist singleton automatisch thread-safe?
Nein.
Spring singleton macht deinen Code nicht automatisch thread-safe.
Hat ein singleton Bean mutable shared State, können mehrere Threads gleichzeitig darauf zugreifen.
Schlecht:
@Service
public class CounterService {
private int counter = 0;
public int increment() {
return ++counter;
}
}
Das ist nicht thread-safe.
Wichtig:
Spring verwaltet den Bean-Lifecycle — nicht deinen geteilten mutable State.
13. Prototype Scope
Prototype Scope bedeutet:
Spring erzeugt bei jeder Anfrage vom container eine neue Bean-Instanz.
Beispiel:
@Component
@Scope("prototype")
public class ReportBuilder {
}
Jedes Mal, wenn Spring nach ReportBuilder gefragt wird, erzeugt es ein neues Objekt.
context.getBean(ReportBuilder.class) -> neuer ReportBuilder
context.getBean(ReportBuilder.class) -> noch ein neuer ReportBuilder
context.getBean(ReportBuilder.class) -> noch ein neuer ReportBuilder
14. Prototype-Scope-Beispiel
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class JobContext {
private final UUID id = UUID.randomUUID();
public UUID getId() {
return id;
}
}
Wenn du es mehrfach anfragst:
JobContext a = context.getBean(JobContext.class);
JobContext b = context.getBean(JobContext.class);
Dann:
a != b
Es sind verschiedene Instanzen.
15. Singleton vs. prototype
| Scope | Instanz-Verhalten |
|---|---|
| singleton | eine Instanz pro Spring container |
| prototype | neue Instanz bei jeder Anfrage |
Beispiel:
Singleton:
getBean() -> dasselbe Objekt
getBean() -> dasselbe Objekt
Prototype:
getBean() -> neues Objekt
getBean() -> neues Objekt
16. Prototype-Lifecycle
Das ist wichtig.
Bei singleton Beans verwaltet Spring den vollen Lifecycle:
create
inject dependencies
initialize
destroy on context shutdown
Bei prototype Beans erzeugt und initialisiert Spring sie, verwaltet die Zerstörung aber nicht auf dieselbe Weise.
Wichtig:
Spring ruft bei prototype Beans beim Schließen des Application Context nicht automatisch destroy Callbacks auf.
Merksatz:
Spring erzeugt prototype Beans, aber der Aufrufer ist für das Cleanup verantwortlich.
17. Use Cases für Prototype-Beans
Prototype Scope ist nützlich für:
stateful helper objects
builders
temporary processing contexts
objects with short-lived state
Beispiel:
@Component
@Scope("prototype")
public class CsvImportContext {
private int processedRows;
private int failedRows;
public void rowProcessed() {
processedRows++;
}
}
Jeder Import-Job braucht vielleicht einen frischen Context.
18. Die große Prüfungsfalle: Prototype in Singleton injiziert
Das ist eines der wichtigsten Prüfungsthemen.
Beispiel:
@Component
@Scope("prototype")
public class JobContext {
}
@Service
public class JobService {
private final JobContext jobContext;
public JobService(JobContext jobContext) {
this.jobContext = jobContext;
}
}
JobService ist singleton.
JobContext ist prototype.
Frage:
Bekommt
JobServicebei jedem Methodenaufruf einen neuenJobContext?
Antwort:
Nein.
Spring erzeugt JobService einmal beim Startup.
Zu diesem Zeitpunkt injiziert Spring einen JobContext.
Danach bleibt dieselbe JobContext-Instanz im singleton JobService.
19. Warum Prototype-in-Singleton tricky ist
Startup-Flow:
1. Spring erzeugt singleton JobService.
2. JobService braucht JobContext.
3. Spring erzeugt einen prototype JobContext.
4. Spring injiziert ihn in JobService.
5. JobService behält diese Instanz für immer.
Das ist also nicht dynamisch:
@Service
public class JobService {
private final JobContext jobContext;
public void runJob() {
// same jobContext every time
}
}
Merksatz für die Prüfung:
Ein prototype Bean, der in einen singleton injiziert wird, wird einmal zur Erstellungszeit des singleton erzeugt.
20. Wie du aus einem Singleton eine frische Prototype-Instanz bekommst
Braucht ein singleton Bean jedes Mal eine frische prototype-Instanz, nutze:
ObjectProvider<T>
Provider<T>
lookup method injection
scoped proxy
ApplicationContext getBean
Am praktischsten und saubersten:
ObjectProvider<T>
21. ObjectProvider nutzen
@Service
public class JobService {
private final ObjectProvider<JobContext> jobContextProvider;
public JobService(ObjectProvider<JobContext> jobContextProvider) {
this.jobContextProvider = jobContextProvider;
}
public void runJob() {
JobContext jobContext = jobContextProvider.getObject();
// fresh prototype instance
}
}
Jetzt liefert jeder Aufruf von:
jobContextProvider.getObject()
eine neue prototype Bean von Spring.
22. Warum ObjectProvider nützlich ist
ObjectProvider ist nützlich für:
lazy dependency access
optional dependencies
getting fresh prototype instances
getting dependencies only when needed
accessing all beans of a type
Merksatz:
ObjectProviderlässt einen singleton Spring später um eine Dependency fragen.
23. Provider<T>
Java bietet auch Provider-ähnlichen Zugriff.
Beispiel:
@Service
public class JobService {
private final Provider<JobContext> jobContextProvider;
public JobService Provider<JobContext> jobContextProvider) {
this.jobContextProvider = jobContextProvider;
}
public void runJob() {
JobContext jobContext = jobContextProvider.get();
}
}
Konzeptionell ähnlich:
Frag den Provider bei Bedarf um eine frische Dependency.
In Spring-Projekten ist ObjectProvider üblich.
24. ApplicationContext-Lookup
Das funktioniert auch:
@Service
public class JobService {
private final ApplicationContext applicationContext;
public JobService(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void runJob() {
JobContext jobContext = applicationContext.getBean(JobContext.class);
}
}
Das ist aber meist weniger sauber.
Warum?
Weil der Service jetzt direkt vom Spring container abhängt.
Besser:
ObjectProvider<JobContext>
Merksatz:
Bevorzuge
ObjectProviderstattApplicationContextfür prototype-Lookup.
25. Request Scope
Request Scope ist ein Web Scope.
Es bedeutet:
Eine Bean-Instanz pro HTTP-Request.
Beispiel:
@Component
@RequestScope
public class RequestContext {
private final String requestId = UUID.randomUUID().toString();
public String getRequestId() {
return requestId;
}
}
Jeder HTTP-Request bekommt seinen eigenen RequestContext.
Request 1 -> RequestContext A
Request 2 -> RequestContext B
Request 3 -> RequestContext C
26. Use Cases für Request Scope
Request-scoped Beans können request-spezifische Daten speichern:
request ID
current tenant
request metadata
correlation ID
temporary request state
Beispiel:
@Component
@RequestScope
public class TenantContext {
private String tenantId;
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
}
Wichtig:
Request-spezifischer State gehört nicht in singleton Services.
27. Session Scope
Session Scope ist auch ein Web Scope.
Es bedeutet:
Eine Bean-Instanz pro HTTP-Session.
Beispiel:
@Component
@SessionScope
public class ShoppingCart {
private final List<String> items = new ArrayList<>();
public void addItem(String item) {
items.add(item);
}
public List<String> getItems() {
return items;
}
}
Jede User-Session bekommt ihren eigenen ShoppingCart.
User session A -> ShoppingCart A
User session B -> ShoppingCart B
28. Request vs. session Scope
| Scope | Lebensdauer |
|---|---|
| request | ein HTTP-Request |
| session | eine HTTP-Session |
Beispiel:
Request scope:
neue Bean für jeden Request
Session scope:
dieselbe Bean für die Session desselben Users
Request Scope ist kürzer.
Session Scope ist länger.
29. Web Scopes brauchen Web Context
Request und session Scope funktionieren in web-aware Spring-Anwendungen.
Versuchst du request Scope in einer Nicht-Web-Anwendung, kann es fehlschlagen — es gibt keinen HTTP-Request.
Wichtig:
Request und session Scope brauchen einen Web Application Context.
30. Request Scope in Singleton injizieren
Das ist ein weiteres wichtiges Thema.
Die meisten Controller und Services sind standardmäßig singleton.
Beispiel:
@Service
public class AuditService {
private final RequestContext requestContext;
public AuditService(RequestContext requestContext) {
this.requestContext = requestContext;
}
}
AuditService ist singleton.
RequestContext ist request-scoped.
Frage:
Wie kann ein singleton einen request-scoped Bean halten, wenn sich der Request jedes Mal ändert?
Antwort:
Spring injiziert meist einen Proxy.
31. Was ist ein scoped proxy?
Ein scoped proxy ist ein Proxy-Objekt, das an Stelle der echten scoped Bean steht.
Der singleton bekommt den Proxy.
Zur Laufzeit findet der Proxy die richtige Bean für den aktuellen Request oder die aktuelle Session.
Mental Model:
AuditService singleton
-> RequestContext proxy
-> echter RequestContext für den aktuellen HTTP-Request
Das injizierte Objekt bleibt stabil, aber das Ziel dahinter wechselt pro Request.
32. Request Scope mit Proxy
Beispiel:
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestContext {
}
Oder einfacher:
@Component
@RequestScope
public class RequestContext {
}
@RequestScope ist eine composed Annotation, die üblicherweise scoped-proxy-Verhalten nutzt.
33. Session Scope mit Proxy
Beispiel:
@Component
@SessionScope
public class ShoppingCart {
}
Ein singleton Service kann ihn injizieren, weil Spring einen Proxy nutzen kann.
Beispiel:
@Service
public class CartService {
private final ShoppingCart shoppingCart;
public CartService(ShoppingCart shoppingCart) {
this.shoppingCart = shoppingCart;
}
}
Der injizierte ShoppingCart kann tatsächlich ein Proxy sein, der an den session-spezifischen Cart delegiert.
34. Warum es scoped proxy gibt
Ohne Proxy:
Singleton Bean wird beim Startup erzeugt.
Request Bean existiert nur während eines HTTP-Requests.
Beim Startup gibt es keinen Request.
Spring kann also die echte Request Bean nicht direkt injizieren.
Mit Proxy:
Spring injiziert beim Startup einen Proxy.
Während jedes Requests delegiert der Proxy an das richtige request-scoped Objekt.
Merksatz:
Scoped proxy lässt einen langlebigen Bean von einem kurzlebigen scoped Bean abhängen.
35. Scope-Annotations
Häufige Annotations:
@Scope("singleton")
@Scope("prototype")
@RequestScope
@SessionScope
@ApplicationScope
Beispiele:
@Component
@Scope("prototype")
public class ReportBuilder {
}
@Component
@RequestScope
public class RequestContext {
}
@Component
@SessionScope
public class ShoppingCart {
}
36. Singleton Scope mit @Scope
Das ist explizit, aber meist unnötig:
@Component
@Scope("singleton")
public class OrderService {
}
Weil singleton bereits der Default ist.
Meist reicht:
@Service
public class OrderService {
}
37. Prototype Scope mit @Scope
Nutze:
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ReportBuilder {
}
oder:
@Component
@Scope("prototype")
public class ReportBuilder {
}
Die Konstante ist sicherer als ein String.
38. Request Scope mit @Scope
Du siehst vielleicht:
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST)
public class RequestContext {
}
oder einfach:
@Component
@RequestScope
public class RequestContext {
}
@RequestScope ist leichter zu lesen.
39. Session Scope mit @Scope
Du siehst vielleicht:
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION)
public class ShoppingCart {
}
oder einfach:
@Component
@SessionScope
public class ShoppingCart {
}
40. Application Scope
Application Scope bedeutet:
Eine Bean-Instanz pro ServletContext.
Beispiel:
@Component
@ApplicationScope
public class ApplicationStats {
}
Das ist ein Web-Application-Scope.
Er wird seltener genutzt als singleton.
Unterschied:
singleton = eine pro Spring container
application = eine pro ServletContext
In vielen einfachen Apps ist der Unterschied kaum sichtbar.
41. WebSocket Scope
WebSocket Scope bedeutet:
Eine Bean-Instanz pro WebSocket-Session.
Das ist für normale REST APIs seltener relevant.
Für die Prüfung fokussiere dich mehr auf:
singleton
prototype
request
session
42. Praxisbeispiel: Request ID
Request-scoped Bean:
@Component
@RequestScope
public class RequestInfo {
private final String requestId = UUID.randomUUID().toString();
public String getRequestId() {
return requestId;
}
}
Service:
@Service
public class LoggingService {
private final RequestInfo requestInfo;
public LoggingService(RequestInfo requestInfo) {
this.requestInfo = requestInfo;
}
public void log(String message) {
System.out.println(requestInfo.getRequestId() + ": " + message);
}
}
Jeder Request bekommt eine andere Request ID.
43. Praxisbeispiel: Tenant Context
Für eine Multi-Tenant-App:
@Component
@RequestScope
public class TenantContext {
private String tenantId;
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
}
Ein Filter kann die Tenant ID aus einem Header setzen:
X-Tenant-Id: tenant-123
Dann können Services während des Requests auf den Tenant Context zugreifen.
44. Vorsicht mit Request Context
Request-scoped Daten solltest du vorsichtig nutzen.
Verstecke nicht zu viel Business Logic im request-scoped Context.
Gute Nutzung:
request ID
tenant ID
current request metadata
Schlechte Nutzung:
large business state
important domain data
database transaction state
Business Logic gehört in Services.
45. Praxisbeispiel: Shopping Cart
Für klassische Web-Apps:
@Component
@SessionScope
public class ShoppingCart {
private final List<Long> productIds = new ArrayList<>();
public void add(Long productId) {
productIds.add(productId);
}
public List<Long> getProductIds() {
return productIds;
}
}
Jede User-Session hat einen separaten Cart.
Für stateless REST APIs ist session Scope seltener.
46. Scopes und REST APIs
In modernen REST APIs sind viele Anwendungen stateless.
Häufige Scopes:
singleton for services
singleton for repositories
request scope sometimes for request metadata
prototype rarely
session scope rarely
Spring Services und Repositories sind meist singleton.
Das ist normal.
47. Scope und Thread Safety
Wichtige Regel:
Singleton Beans können von vielen Threads genutzt werden.
Deshalb:
Speichere keinen request-spezifischen mutable State in singleton-Feldern.
Gute singleton-Felder:
repository dependency
service dependency
configuration properties
Clock
ObjectMapper
PasswordEncoder
Schlechte singleton-Felder:
currentUserId
currentRequest
currentOrderId
temporary calculation result
48. Prüfungsfrage: Default Scope
Frage:
Was ist der Default Bean Scope in Spring?
Antwort:
Der Default Bean Scope ist singleton.
49. Prüfungsfrage: Spring singleton
Frage:
Was bedeutet singleton in Spring?
Antwort:
Singleton bedeutet: Spring erzeugt eine Bean-Instanz pro Spring IoC container.
50. Prüfungsfrage: Spring singleton vs. Java-Singleton-Pattern
Frage:
Ist Spring singleton dasselbe wie das Java-Singleton-Pattern?
Antwort:
Nein. Spring singleton bedeutet eine Bean-Instanz pro Spring container. Das Java-Singleton-Pattern bedeutet meist eine Instanz pro JVM, gesteuert über statischen Zugriff.
51. Prüfungsfrage: Prototype Scope
Frage:
Was bedeutet prototype Scope?
Antwort:
Prototype Scope bedeutet: Spring erzeugt bei jeder Anfrage vom container eine neue Bean-Instanz.
52. Prüfungsfrage: Prototype-Zerstörung
Frage:
Verwaltet Spring den vollen Destruction-Lifecycle von prototype Beans?
Antwort:
Nein. Spring erzeugt und initialisiert prototype Beans, verwaltet ihre Zerstörung beim Schließen des Context aber nicht automatisch. Der Aufrufer ist für das Cleanup verantwortlich.
53. Prüfungsfrage: Prototype in Singleton
Frage:
@Component
@Scope("prototype")
public class JobContext {
}
@Service
public class JobService {
private final JobContext jobContext;
public JobService(JobContext jobContext) {
this.jobContext = jobContext;
}
}
Bekommt JobService bei jedem Methodenaufruf einen neuen JobContext?
Antwort:
Nein. JobService ist singleton — Spring erzeugt ihn einmal und injiziert zur Erstellungszeit einen prototype JobContext. Dieselbe JobContext-Instanz wird in diesem singleton wiederverwendet.
54. Prüfungsfrage: Frische Prototype-Instanz
Frage:
Wie kann ein singleton jedes Mal eine frische prototype-Instanz bekommen?
Antwort:
Nutze ObjectProvider<T>, Provider<T>, lookup method injection oder fordere die Bean über ApplicationContext an. ObjectProvider<T> ist meist die saubere Spring-spezifische Lösung.
55. Prüfungsfrage: Request Scope
Frage:
Was bedeutet request Scope?
Antwort:
Request Scope bedeutet: Spring erzeugt eine Bean-Instanz pro HTTP-Request.
56. Prüfungsfrage: Session Scope
Frage:
Was bedeutet session Scope?
Antwort:
Session Scope bedeutet: Spring erzeugt eine Bean-Instanz pro HTTP-Session.
57. Prüfungsfrage: Scoped proxy
Frage:
Warum brauchen wir einen scoped proxy?
Antwort:
Ein scoped proxy erlaubt einem langlebigen Bean — z. B. einem singleton Service — von einem kurzlebigen Bean abzuhängen, z. B. einem request-scoped Bean. Der singleton bekommt einen Proxy, und der Proxy delegiert an die richtige echte Bean für den aktuellen Request oder die aktuelle Session.
58. Prüfungsfrage: Stateful Singleton
Frage:
Warum ist das gefährlich?
@Service
public class UserService {
private Long currentUserId;
}
Antwort:
UserService ist standardmäßig singleton und wird über Requests hinweg geteilt. currentUserId ist mutable request-spezifischer State. Mehrere Threads oder Requests können ihn überschreiben und falsches Verhalten verursachen. Singleton Beans sollten meist stateless sein.
59. Prüfungsfrage: Request Scope in Nicht-Web-App
Frage:
Kann ich request Scope in einer Nicht-Web-Anwendung nutzen?
Antwort:
Request Scope braucht einen web-aware Context und einen aktiven HTTP-Request. In einer Nicht-Web-Anwendung macht request Scope meist keinen Sinn und kann fehlschlagen.
60. Interview-Antwort
Frage:
Was sind Bean Scopes in Spring?
Gute Antwort:
Bean Scopes definieren, wie lange ein Bean lebt und wie viele Instanzen Spring erzeugt. Der Default Scope ist singleton — das bedeutet eine Bean-Instanz pro Spring container. Prototype Scope erzeugt bei jeder Anfrage eine neue Bean-Instanz. In Web-Anwendungen erzeugt request Scope eine Bean pro HTTP-Request, und session Scope eine Bean pro HTTP-Session.
61. Interview-Antwort
Frage:
Was ist der Unterschied zwischen singleton und prototype Scope?
Gute Antwort:
Singleton Scope bedeutet: Spring erzeugt eine Bean-Instanz pro Application Context und nutzt sie überall wieder. Prototype Scope bedeutet: Spring erzeugt bei jeder Anfrage vom container eine neue Bean-Instanz. Singleton ist der Default und wird häufig für Services und Repositories genutzt. Prototype ist nützlich für stateful, kurzlebige Objekte.
62. Interview-Antwort
Frage:
Was passiert, wenn ein prototype Bean in einen singleton Bean injiziert wird?
Gute Antwort:
Der prototype Bean wird einmal erzeugt, wenn der singleton Bean erzeugt wird. Der singleton behält dann dieselbe prototype-Instanz. Er bekommt nicht bei jedem Methodenaufruf einen neuen prototype. Braucht der singleton jedes Mal eine frische prototype-Instanz, sollte er ObjectProvider, Provider, lookup method injection oder einen anderen lazy Lookup-Mechanismus nutzen.
63. Interview-Antwort
Frage:
Warum sollten singleton Beans meist stateless sein?
Gute Antwort:
Singleton Beans werden im gesamten Spring container geteilt und können gleichzeitig von mehreren Threads oder Requests genutzt werden. Speichert ein singleton request-spezifischen mutable State in Feldern, kann ein Request Daten eines anderen Requests überschreiben. Das kann Race Conditions und falsches Verhalten verursachen. Deshalb sollten Services und Repositories meist stateless sein und request-spezifische Daten in Methodenparametern, lokalen Variablen oder request-scoped Objekten halten.
64. Interview-Antwort
Frage:
Was ist ein scoped proxy?
Gute Antwort:
Ein scoped proxy ist ein Objekt, das Spring statt der echten scoped Bean injiziert. Es ist nützlich, wenn ein langlebiger Bean — z. B. ein singleton Service — von einem kürzerlebigen Bean abhängt, z. B. einem request-scoped oder session-scoped Bean. Der Proxy bleibt gleich, delegiert aber Aufrufe an die richtige echte Bean für den aktuellen Request oder die aktuelle Session.
65. Kleine Code-Übung
Erstelle einen prototype Bean:
@Component
@Scope("prototype")
public class ImportContext {
private final UUID id = UUID.randomUUID();
public UUID getId() {
return id;
}
}
Schlechte singleton-Nutzung:
@Service
public class ImportService {
private final ImportContext importContext;
public ImportService(ImportContext importContext) {
this.importContext = importContext;
}
public void runImport() {
System.out.println(importContext.getId());
}
}
Frage:
Warum erzeugt das nicht bei jedem Import einen neuen
ImportContext?
Antwort:
Weil ImportService singleton ist. Spring erzeugt ihn einmal und injiziert zu diesem Zeitpunkt einen prototype ImportContext. Dieselbe Instanz wird bei jedem Methodenaufruf genutzt.
Besser:
@Service
public class ImportService {
private final ObjectProvider<ImportContext> importContextProvider;
public ImportService(ObjectProvider<ImportContext> importContextProvider) {
this.importContextProvider = importContextProvider;
}
public void runImport() {
ImportContext importContext = importContextProvider.getObject();
System.out.println(importContext.getId());
}
}
Jetzt kann jeder Import einen frischen ImportContext bekommen.
66. Kleine Bug-Übung
Problem:
@Service
public class CheckoutService {
private Long currentCustomerId;
public void checkout(Long customerId) {
this.currentCustomerId = customerId;
}
}
Frage:
Was ist falsch?
Antwort:
CheckoutService ist standardmäßig singleton. Das Feld currentCustomerId speichert request-spezifischen mutable State. Rufen mehrere User den Service gleichzeitig auf, können sie die Daten des jeweils anderen überschreiben. Nutze stattdessen Methodenparameter oder request-scoped Context.
Besser:
@Service
public class CheckoutService {
public void checkout(Long customerId) {
Long currentCustomerId = customerId;
// use local variable
}
}
Übungsfragen
Frage 1
Was ist ein Bean Scope?
Antwort:
Ein Bean Scope definiert, wie lange ein Spring Bean lebt und wie viele Instanzen Spring erzeugt.
Frage 2
Was ist der Default Bean Scope in Spring?
Antwort:
Der Default Bean Scope ist singleton.
Frage 3
Was bedeutet singleton in Spring?
Antwort:
Singleton bedeutet: Spring erzeugt eine Bean-Instanz pro Spring IoC container.
Frage 4
Ist Spring singleton dasselbe wie das Java-Singleton-Pattern?
Antwort:
Nein. Spring singleton bedeutet eine Bean-Instanz pro Spring container. Das Java-Singleton-Pattern bedeutet meist eine Instanz pro JVM, gesteuert über statischen Zugriff.
Frage 5
Warum sollten singleton Services meist stateless sein?
Antwort:
Singleton Services sollten meist stateless sein, weil sie über Requests und Threads hinweg geteilt werden. Mutable request-spezifischer State in Feldern kann Race Conditions und falsche Daten verursachen.
Frage 6
Ist singleton Scope automatisch thread-safe?
Antwort:
Nein. Singleton Scope macht einen Bean nicht automatisch thread-safe. Thread Safety hängt davon ab, wie der Bean implementiert ist.
Frage 7
Was bedeutet prototype Scope?
Antwort:
Prototype Scope bedeutet: Spring erzeugt bei jeder Anfrage vom container eine neue Bean-Instanz.
Frage 8
Verwaltet Spring die Zerstörung von prototype Beans automatisch?
Antwort:
Nein. Spring erzeugt und initialisiert prototype Beans, verwaltet ihre Zerstörung beim Schließen des Context aber nicht automatisch.
Frage 9
Was passiert, wenn ein prototype Bean in einen singleton Bean injiziert wird?
Antwort:
Der prototype Bean wird einmal erzeugt, wenn der singleton erzeugt wird. Der singleton behält dieselbe Instanz.
Frage 10
Wie kann ein singleton jedes Mal eine frische prototype Bean bekommen?
Antwort:
Ein singleton kann eine frische prototype Bean über ObjectProvider<T>, Provider<T>, lookup method injection oder ApplicationContext.getBean() bekommen.
Frage 11
Wofür ist ObjectProvider nützlich?
Antwort:
ObjectProvider ist nützlich für lazy dependency access, optionale Dependencies und frische prototype-Instanzen aus einem singleton.
Frage 12
Was bedeutet request Scope?
Antwort:
Request Scope bedeutet eine Bean-Instanz pro HTTP-Request.
Frage 13
Was bedeutet session Scope?
Antwort:
Session Scope bedeutet eine Bean-Instanz pro HTTP-Session.
Frage 14
Was ist der Unterschied zwischen request Scope und session Scope?
Antwort:
Request Scope erzeugt für jeden HTTP-Request eine neue Bean. Session Scope behält eine Bean für die Dauer der HTTP-Session eines Users.
Frage 15
Was ist ein scoped proxy?
Antwort:
Ein scoped proxy ist ein Proxy-Objekt, das an Stelle einer scoped Bean injiziert wird. Er delegiert Aufrufe an die richtige echte Bean für den aktuellen Scope.
Frage 16
Warum ist ein scoped proxy nützlich?
Antwort:
Ein scoped proxy ist nützlich, wenn ein langlebiger Bean — z. B. ein singleton — von einem kurzlebigen Bean abhängt, z. B. einem request-scoped oder session-scoped Bean.
Frage 17
Kann request Scope ohne HTTP-Request genutzt werden?
Antwort:
Meist nein. Request Scope braucht einen web-aware Context und einen aktiven HTTP-Request.
Frage 18
Was ist falsch daran, currentUserId als Feld in einem singleton Service zu speichern?
Antwort:
currentUserId ist request-spezifischer mutable State. Weil der Service singleton ist und geteilt wird, können mehrere Requests das Feld überschreiben und falsches Verhalten verursachen.
Frage 19
Welche Scopes sind für die Zertifizierung am wichtigsten?
Antwort:
Für die Zertifizierung sind diese Scopes am wichtigsten:
singleton
prototype
request
session
Frage 20
Welcher Scope wird meist für normale Services und Repositories genutzt?
Antwort:
Normale Services und Repositories sind meist singleton Beans.
Merksätze zum Mitnehmen
- Ein Bean Scope steuert, wie lange ein Bean lebt und wie viele Instanzen Spring erzeugt.
- Der Default Bean Scope ist singleton.
- Spring singleton bedeutet eine Bean-Instanz pro Spring container.
- Spring singleton ist nicht dasselbe wie das Java-Singleton-Pattern.
- Singleton Beans sollten meist stateless sein.
- Singleton Scope macht Code nicht automatisch thread-safe.
- Prototype Scope erzeugt bei jeder Anfrage eine neue Bean.
- Spring zerstört prototype Beans nicht automatisch.
- Ein in einen singleton injizierter prototype wird einmal zur Erstellungszeit des singleton erzeugt.
- Nutze
ObjectProvider, wenn ein singleton frische prototype-Instanzen braucht. - Request Scope bedeutet eine Bean pro HTTP-Request.
- Session Scope bedeutet eine Bean pro HTTP-Session.
- Ein scoped proxy lässt einen singleton von einem request-scoped oder session-scoped Bean abhängen.
- Speichere keinen request-spezifischen mutable State in singleton-Service-Feldern.