Suche…


Singleton-Bereich

Wenn eine Bean mit Singleton-Bereich definiert ist, wird im Spring-Container nur eine einzige Objektinstanz initialisiert. Alle Anforderungen an diese Bean geben dieselbe gemeinsam genutzte Instanz zurück. Dies ist der Standardbereich bei der Definition einer Bean.

Angesichts der folgenden MyBean-Klasse:

public class MyBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyBean.class);
    private String property;

    public MyBean(String property) {
        this.property = property;
        LOGGER.info("Initializing {} bean...", property);
    }

    public String getProperty() {
        return this.property;
    }

    public void setProperty(String property) {
        this.property = property;
    }
}

Wir können eine Singleton-Bean mit der @Bean-Annotation definieren:

@Configuration
public class SingletonConfiguration {

    @Bean
    public MyBean singletonBean() {
        return new MyBean("singleton");
    } 
}

Im folgenden Beispiel wird dieselbe Bean zweimal aus dem Spring-Kontext abgerufen:

MyBean singletonBean1 = context.getBean("singletonBean", MyBean.class);
singletonBean1.setProperty("changed property");

MyBean singletonBean2 = context.getBean("singletonBean", MyBean.class);

Beim Protokollieren der Eigenschaft singletonBean2 wird die Nachricht "geänderte Eigenschaft" angezeigt, da wir gerade dieselbe gemeinsam genutzte Instanz abgerufen haben.

Da die Instanz von verschiedenen Komponenten gemeinsam genutzt wird, wird empfohlen, den Einzelbereichs für statuslose Objekte zu definieren.

Faule Singleton-Bohnen

Standardmäßig werden Singleton-Beans vorinstanziert. Daher wird die Shared Object-Instanz erstellt, wenn der Spring-Container erstellt wird. Wenn wir die Anwendung starten, wird die Meldung "Singleton Bean wird initialisiert ..." angezeigt.

Wenn die Bean nicht vorinstanziert werden soll, können wir die @Lazy-Annotation zur Bean-Definition hinzufügen. Dadurch wird verhindert, dass die Bean erstellt wird, bis sie zum ersten Mal angefordert wird.

@Bean
@Lazy
public MyBean lazySingletonBean() {
    return new MyBean("lazy singleton");
}

Wenn wir nun den Spring-Container starten, wird keine Meldung "Lazy Singleton Bean initialisieren ..." angezeigt. Die Bean wird erst erstellt, wenn sie zum ersten Mal angefordert wird:

logger.info("Retrieving lazy singleton bean...");
context.getBean("lazySingletonBean");

Wenn wir die Anwendung mit definierten Singleton- und Lazy-Singleton-Beans ausführen, werden folgende Meldungen ausgegeben:

Initializing singleton bean...
Retrieving lazy singleton bean...
Initializing lazy singleton bean...

Prototypumfang

Ein Bean für Prototyp-Bereiche wird beim Start des Spring-Containers nicht vorab erstellt. Stattdessen wird jedes Mal eine neue Instanz erstellt, wenn eine Anforderung zum Abrufen dieser Bean an den Container gesendet wird. Dieser Bereich wird für stateful-Objekte empfohlen, da der Status nicht von anderen Komponenten gemeinsam genutzt wird.

Um ein Bean für Prototyp-Bereiche zu definieren, müssen wir die @Scope-Annotation hinzufügen und den gewünschten Bereich angeben.

Angesichts der folgenden MyBean-Klasse:

public class MyBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyBean.class);
    private String property;

    public MyBean(String property) {
        this.property = property;
        LOGGER.info("Initializing {} bean...", property);
    }

    public String getProperty() {
        return this.property;
    }

    public void setProperty(String property) {
        this.property = property;
    }
}

Wir definieren eine Bean-Definition und geben deren Umfang als Prototyp an:

@Configuration
public class PrototypeConfiguration {

    @Bean
    @Scope("prototype")
    public MyBean prototypeBean() {
        return new MyBean("prototype");
    }
}

Um zu sehen, wie es funktioniert, rufen wir die Bean aus dem Spring-Container ab und legen einen anderen Wert für das Eigenschaftsfeld fest. Als Nächstes rufen wir die Bean erneut aus dem Container ab und prüfen deren Wert:

MyBean prototypeBean1 = context.getBean("prototypeBean", MyBean.class);
prototypeBean1.setProperty("changed property");

MyBean prototypeBean2 = context.getBean("prototypeBean", MyBean.class);

logger.info("Prototype bean 1 property: " + prototypeBean1.getProperty());
logger.info("Prototype bean 2 property: " + prototypeBean2.getProperty());

Mit dem folgenden Ergebnis können wir sehen, wie eine neue Instanz für jede Bean-Anfrage erstellt wurde:

Initializing prototype bean...
Initializing prototype bean...
Prototype bean 1 property: changed property
Prototype bean 2 property: prototype

Ein häufiger Fehler ist die Annahme, dass die Bean pro Aufruf oder pro Thread neu erstellt wird. Dies ist NICHT der Fall. Stattdessen wird eine Instanz PER INJECTION erstellt (oder aus dem Kontext abgerufen). Wenn eine Bean für Prototype-Bereiche immer nur in eine einzelne Bean eingebettet wird, gibt es nur eine Instanz dieser Bean für Prototyp-Bereiche.

Spring verwaltet nicht den gesamten Lebenszyklus einer Prototyp-Bean: Der Container instanziiert, konfiguriert, dekoriert und baut ein Prototypobjekt auf andere Weise zusammen, übergibt es an den Client und hat dann keine weiteren Informationen über diese Prototypinstanz.

Zusätzliche Bereiche in webfähigen Kontexten

Es gibt verschiedene Bereiche, die nur in einem webfähigen Anwendungskontext verfügbar sind:

  • request - Neue Bean-Instanz wird per HTTP-Anfrage erstellt
  • session - neue Bean-Instanz wird pro HTTP-Sitzung erstellt
  • application - Neue Bean-Instanz wird per ServletContext
  • globalSession - neue Bean-Instanz wird pro globale Sitzung in der Portlet-Umgebung erstellt (in der Servlet-Umgebung entspricht der globale Sitzungsbereich dem Sitzungsbereich)
  • websocket - Neue Bean-Instanz wird pro WebSocket-Sitzung erstellt

Für die Deklaration und den Zugriff auf Web-Beans in der Spring Web MVC-Umgebung sind keine zusätzlichen Einstellungen erforderlich.

XML-Konfiguration

<bean id="myRequestBean" class="OneClass" scope="request"/>
<bean id="mySessionBean" class="AnotherClass" scope="session"/>
<bean id="myApplicationBean" class="YetAnotherClass" scope="application"/>
<bean id="myGlobalSessionBean" class="OneMoreClass" scope="globalSession"/>

Java-Konfiguration (vor Spring 4.3)

@Configuration
public class MyConfiguration {

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public OneClass myRequestBean() {
        return new OneClass();
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public AnotherClass mySessionBean() {
        return new AnotherClass();
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public YetAnotherClass myApplicationBean() {
        return new YetAnotherClass();
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public OneMoreClass myGlobalSessionBean() {
        return new OneMoreClass();
    }
}

Java-Konfiguration (nach Spring 4.3)

@Configuration
public class MyConfiguration {

    @Bean
    @RequestScope
    public OneClass myRequestBean() {
        return new OneClass();
    }

    @Bean
    @SessionScope
    public AnotherClass mySessionBean() {
        return new AnotherClass();
    }

    @Bean
    @ApplicationScope
    public YetAnotherClass myApplicationBean() {
        return new YetAnotherClass();
    }
}

Anmerkungsgesteuerte Komponenten

@Component
@RequestScope
public class OneClass {
    ...
}

@Component
@SessionScope
public class AnotherClass {
    ...
}

@Component
@ApplicationScope
public class YetAnotherClass {
    ...
}

@Component
@Scope(scopeName = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OneMoreClass {
    ...
}

@Component
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AndOneMoreClass {
    ...
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow