Zoeken…


Singleton scope

Als een bean is gedefinieerd met singleton scope, wordt er slechts één objectinstantie geïnitialiseerd in de Spring-container. Alle aanvragen voor deze bean retourneren dezelfde gedeelde instantie. Dit is het standaardbereik bij het definiëren van een boon.

Gegeven de volgende 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;
    }
}

We kunnen een singleton bean definiëren met de @Bean-annotatie:

@Configuration
public class SingletonConfiguration {

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

In het volgende voorbeeld wordt dezelfde bean tweemaal uit de context Spring opgehaald:

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

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

Bij het loggen van de eigenschap singletonBean2 wordt het bericht "gewijzigde eigenschap" weergegeven, omdat we net dezelfde gedeelde instantie hebben opgehaald.

Omdat de instantie wordt gedeeld tussen verschillende componenten, wordt het aanbevolen om een singleton scope voor stateless objecten te definiëren.

Luie singleton bonen

Standaard worden singletonbonen vooraf gemaakt. Daarom wordt de instantie van het gedeelde object gemaakt wanneer de Spring-container wordt gemaakt. Als we de toepassing starten, wordt het bericht "Bezig met initialiseren singleton bean ..." weergegeven.

Als we niet willen dat de bean vooraf wordt geïnstantieerd, kunnen we de @Lazy-annotatie toevoegen aan de beandefinitie. Dit voorkomt dat de boon wordt gemaakt totdat deze voor het eerst wordt aangevraagd.

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

Als we nu de Spring-container starten, wordt er geen bericht 'Initializing lazy singleton bean ...' weergegeven. De boon wordt pas gemaakt als deze voor de eerste keer wordt aangevraagd:

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

Als we de toepassing uitvoeren met zowel singleton als luie singletonbonen gedefinieerd, worden de volgende berichten geproduceerd:

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

Prototype scope

Een boon met een prototype is niet vooraf gemaakt bij het opstarten van de Spring-container. In plaats daarvan wordt een nieuwe nieuwe instantie gemaakt telkens wanneer een verzoek om deze bean op te halen naar de container wordt verzonden. Deze scope wordt aanbevolen voor stateful objecten, omdat de status ervan niet wordt gedeeld door andere componenten.

Om een prototype-scoped bean te definiëren, moeten we de @Scope-annotatie toevoegen, met vermelding van het gewenste bereik.

Gegeven de volgende 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;
    }
}

We definiëren een bonendefinitie en vermelden het toepassingsgebied ervan als prototype:

@Configuration
public class PrototypeConfiguration {

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

Om te zien hoe het werkt, halen we de bean uit de Spring-container en stellen we een andere waarde in voor het eigenschappenveld. Vervolgens halen we de boon opnieuw uit de container en zoeken we de waarde op:

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());

Kijkend naar het volgende resultaat, kunnen we zien hoe een nieuw exemplaar is gemaakt op elk beanverzoek:

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

Een veel voorkomende fout is om aan te nemen dat de boon opnieuw wordt gemaakt per aanroep of per thread, dit is NIET het geval. In plaats daarvan wordt een exemplaar PER INJECTIE gemaakt (of opgehaald uit de context). Als een Prototype-scoopboon slechts ooit in een enkele singletonboon wordt geïnjecteerd, zal er slechts één exemplaar van die Prototype-scoopboon zijn.

Spring beheert niet de volledige levenscyclus van een prototype bean: de container instantieert, configureert, decoreert en anderszins assembleert een prototypeobject, overhandigt het aan de klant en heeft dan geen verdere kennis van dat prototype-exemplaar.

Extra bereik in webbewuste contexten

Er zijn verschillende bereiken die alleen beschikbaar zijn in een webbewuste toepassingscontext:

  • request - er wordt een nieuw beaninstantie gemaakt per HTTP-aanvraag
  • sessie - er wordt een nieuwe bean-instantie gemaakt per HTTP-sessie
  • applicatie - er wordt een nieuwe ServletContext gemaakt per ServletContext
  • globalSession - er wordt een nieuwe beaninstantie gemaakt per globale sessie in Portlet-omgeving (in Servlet-omgeving is het globale sessiebereik gelijk aan sessiebereik)
  • websocket - er wordt een nieuwe beaninstantie gemaakt per WebSocket-sessie

Er is geen extra installatie vereist om bonen met webbereik te declareren en te openen in Spring Web MVC-omgeving.

XML-configuratie

<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-configuratie (voorafgaand aan voorjaar 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-configuratie (na voorjaar 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();
    }
}

Annotatie-aangedreven componenten

@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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow