In Spring spielt der Bean-Scope eine entscheidende Rolle bei der Verwaltung des Lebenszyklus und der Sichtbarkeit von Beans. Der Scope einer Bean definiert, wie und wann eine Bean instanziiert und verwendet wird. In einer typischen Spring-Anwendung gibt es verschiedene Scopes, die je nach Anforderung eingesetzt werden können. Spring Boot übernimmt die Mechanismen von Spring, erweitert sie aber um einige praktische Funktionen für den Umgang mit Scopes, insbesondere im Hinblick auf webbasierte Anwendungen.
Der Scope einer Bean bestimmt, wie oft eine Instanz dieser Bean erstellt wird und in welchem Kontext sie verfügbar ist. Standardmäßig verwendet Spring den Singleton-Scope, bei dem nur eine Instanz der Bean für den gesamten ApplicationContext erstellt wird. Neben Singleton gibt es jedoch auch andere Scopes, die in verschiedenen Anwendungsszenarien sinnvoll sind.
Die folgenden Scopes sind in Spring Boot verfügbar:
Singleton ist der Standard-Scope in Spring. Eine
Bean im Singleton-Scope wird nur einmal pro
ApplicationContext erstellt und für alle Anforderungen
wiederverwendet. Dies ist der am häufigsten verwendete Scope, da viele
Beans wie Services oder Repositories oft nur eine Instanz benötigen, um
über den gesamten Lebenszyklus der Anwendung hinweg wiederverwendet zu
werden.
Beispiel: Singleton-Bean
import org.springframework.stereotype.Service;
@Service
public class SingletonService {
public SingletonService() {
System.out.println("SingletonService wird instanziiert.");
}
public String getServiceMessage() {
return "Singleton Instance";
}
}In diesem Beispiel wird die SingletonService-Bean nur
einmal beim Starten der Anwendung instanziiert, unabhängig davon, wie
oft sie im Verlauf der Anwendung angefordert wird.
Bei einer Bean im Prototype-Scope wird bei jeder Anforderung eine neue Instanz erstellt. Dies ist nützlich, wenn Sie zustandsbehaftete Beans benötigen, die keine Zustandsinformationen über Anfragen hinweg speichern sollen.
Beispiel: Prototype-Bean
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class PrototypeService {
public PrototypeService() {
System.out.println("PrototypeService wird instanziiert.");
}
public String getServiceMessage() {
return "Prototype Instance";
}
}In diesem Beispiel wird die PrototypeService-Bean bei
jeder Anforderung neu erstellt. Jede Verwendung von
PrototypeService in einer Anwendung führt zu einer neuen
Instanz der Bean.
In Spring Web-Anwendungen gibt es zusätzliche Scopes, die für HTTP-basierte Anwendungen nützlich sind:
Beans im Request-Scope werden für jede HTTP-Anfrage neu instanziiert. Dies ist besonders nützlich, wenn die Bean nur für die Dauer einer einzigen HTTP-Anfrage benötigt wird, z.B. für die Verarbeitung von Formulardaten oder Benutzeranfragen.
Beispiel: Request-Scope
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
@Component
@RequestScope
public class RequestScopedBean {
public RequestScopedBean() {
System.out.println("RequestScopedBean wird pro HTTP-Anfrage instanziiert.");
}
public String getRequestScopedMessage() {
return "Request Scoped Instance";
}
}Jedes Mal, wenn eine HTTP-Anfrage an die Anwendung gesendet wird,
erstellt Spring eine neue Instanz der RequestScopedBean.
Die Bean lebt nur für die Dauer dieser Anfrage und wird danach
verworfen.
Der Session-Scope sorgt dafür, dass eine Bean über die Dauer einer HTTP-Session hinweg erhalten bleibt. Dies ist nützlich, wenn Sie zustandsbehaftete Beans benötigen, die über mehrere Anfragen hinweg dieselbe Session-Information speichern müssen, z.B. Benutzerinformationen während einer Web-Sitzung.
Beispiel: Session-Scope
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;
@Component
@SessionScope
public class SessionScopedBean {
private String sessionId;
public SessionScopedBean() {
this.sessionId = generateSessionId();
System.out.println("SessionScopedBean erstellt mit Session ID: " + sessionId);
}
private String generateSessionId() {
return "SESSION-" + Math.random();
}
public String getSessionId() {
return sessionId;
}
}In diesem Beispiel behält die SessionScopedBean die
sessionId während der gesamten Lebensdauer der
HTTP-Sitzung. Diese Bean wird beim Start einer neuen Sitzung erstellt
und bleibt bis zum Ende der Sitzung erhalten.
Neben den vordefinierten Scopes können Sie auch benutzerdefinierte Scopes in Spring Boot definieren. Dies kann hilfreich sein, wenn Sie spezifische Anforderungen haben, die durch die vorhandenen Scopes nicht abgedeckt sind.
Um einen benutzerdefinierten Scope zu implementieren, müssen Sie eine
Klasse erstellen, die das Scope-Interface von Spring
implementiert, und sie als Bean in den ApplicationContext
registrieren.
Beispiel: Custom Scope
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class CustomScope implements Scope {
private final Map<String, Object> beanMap = new HashMap<>();
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
return beanMap.computeIfAbsent(name, k -> objectFactory.getObject());
}
@Override
public Object remove(String name) {
return beanMap.remove(name);
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
// Not used in this example
}
@Override
public Object resolveContextualObject(String key) {
return null;
}
@Override
public String getConversationId() {
return "custom-scope";
}
}Nach der Implementierung müssen Sie diesen benutzerdefinierten Scope registrieren und verwenden.
Registrierung des Custom Scopes
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@Configuration
public class CustomScopeConfig {
@Bean
@Scope("custom-scope")
public CustomScopedBean customScopedBean() {
return new CustomScopedBean();
}
}Durch die Verwendung eines benutzerdefinierten Scopes können Sie Beans flexibel auf spezifische Anforderungen Ihrer Anwendung zuschneiden.
Standardmäßig Singleton verwenden: Da Singleton-Beans speichereffizient sind und den Overhead der Bean-Instanziierung minimieren, sollten Sie diesen Scope immer dann verwenden, wenn die Bean keinen Zustand speichern muss.
Prototype nur bei Bedarf: Verwenden Sie Prototype-Beans nur, wenn es notwendig ist, zustandsbehaftete Beans zu erstellen. Beachten Sie, dass der Prototyp-Scope im Gegensatz zum Singleton-Scope nicht von Spring verwaltet wird, was die Verwaltung des Bean-Lebenszyklus schwieriger macht.
Web-Scopes gezielt einsetzen: Nutzen Sie
Request und Session-Scopes nur in
Web-Anwendungen, wenn Beans über HTTP-Anfragen oder -Sitzungen hinweg
zustandsbehaftet sein müssen. Diese Scopes sind besonders in Anwendungen
nützlich, die Benutzerinformationen verarbeiten.
Custom Scopes sparsam verwenden: Definieren Sie nur dann eigene Scopes, wenn die vorhandenen Scopes Ihre Anforderungen nicht erfüllen. Die Verwaltung benutzerdefinierter Scopes kann zusätzliche Komplexität verursachen.
Scopes in Spring Boot bieten eine leistungsstarke Möglichkeit, den Lebenszyklus von Beans zu steuern und zu bestimmen, wie und wann sie instanziiert werden. Der richtige Einsatz von Scopes trägt wesentlich zur Effizienz und Flexibilität Ihrer Anwendung bei. Während der Singleton-Scope als Standard die meisten Szenarien abdeckt, bieten spezielle Scopes wie Prototype, Request oder Session zusätzliche Möglichkeiten, Beans für bestimmte Anforderungen zu optimieren.