27 Scopes

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.

27.1 Definition und Bedeutung von Scopes

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:

27.1.1 Singleton Scope (Standard)

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.

27.1.2 Prototype Scope

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.

27.1.3 Scopes in Web-Anwendungen

In Spring Web-Anwendungen gibt es zusätzliche Scopes, die für HTTP-basierte Anwendungen nützlich sind:

27.1.3.1 Request Scope

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.

27.1.3.2 Session Scope

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.

27.1.4 Anwendung von Custom Scopes

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.

27.2 Best Practices bei der Verwendung von Scopes

  1. 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.

  2. 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.

  3. 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.

  4. 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.

27.3 tl;dr

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.