Sök…


Singleton omfattning

Om en böna definieras med singleton-omfattning kommer det endast att finnas en enda objektinstans initialiserad i vårbehållaren. Alla förfrågningar till den här bönan returnerar samma delade instans. Detta är standardomfånget när du definierar en böna.

Följande klassen MyBean:

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;
    }
}

Vi kan definiera en singletonböna med @Bean-kommentaren:

@Configuration
public class SingletonConfiguration {

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

Följande exempel hämtar samma böna två gånger från vårens sammanhang:

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

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

När du loggar in singletonBean2-egenskapen kommer meddelandet "ändrad egenskap" att visas, eftersom vi just har hämtat samma delade instans.

Eftersom instansen delas mellan olika komponenter rekommenderas det att definiera singleton-räckvidd för statslösa objekt.

Lata singletonbönor

Som standard är singletonbönor förinstanserade. Därför skapas den delade objektinstansen när vårbehållaren skapas. Om vi startar applikationen kommer meddelandet "Initialisera singleton bean ..." att visas.

Om vi inte vill att bönan ska förinstanseras kan vi lägga till @Lazy-kommentaren till bönedefinitionen. Detta förhindrar att bönan skapas tills den först begärs.

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

Nu, om vi startar vårbehållaren, kommer inget "Initialisering av lat singleton böna ..." att visas. Bönan skapas inte förrän den begärs för första gången:

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

Om vi kör applikationen med både singleton och lata singletonbönor definierade kommer det att producera följande meddelanden:

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

Prototypomfång

En prototyp-scoped böna är inte för skapad vid Spring container-start. Istället skapas en ny ny instans varje gång en begäran om att hämta den här bönan skickas till behållaren. Denna omfattning rekommenderas för tillståndsfulla objekt, eftersom dess tillstånd inte delas av andra komponenter.

För att definiera en prototyp-scoped böna, måste vi lägga till @Scope-anteckningen och ange vilken typ av omfattning vi vill ha.

Följande klassen MyBean:

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;
    }
}

Vi definierar en bönedefinition och anger dess omfattning som prototyp:

@Configuration
public class PrototypeConfiguration {

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

För att se hur det fungerar hämtar vi bönan från vårbehållaren och ställer in ett annat värde för dess egendomsfält. Därefter hämtar vi bönan igen från behållaren och letar upp dess värde:

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

När vi tittar på följande resultat kan vi se hur en ny instans har skapats på varje bönebegäran:

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

Ett vanligt misstag är att anta att bönan återskapas per invokation eller per tråd, detta är INTE fallet. Istället skapas en instans PER INJEKTION (eller hämtning från sammanhanget). Om en prototypböna bara någonsin injiceras i en singletonböna kommer det bara någonsin att finnas ett exempel på den prototypbönan.

Spring hanterar inte hela livscykeln för en prototypböna: behållaren instanserar, konfigurerar, dekorerar och på annat sätt monterar ett prototypobjekt, överlämnar det till klienten och har då ingen ytterligare kunskap om den prototypinstansen.

Ytterligare tillämpningsområden i webbmedvetna sammanhang

Det finns flera tillämpningsområden som endast är tillgängliga i ett webbmedvetet applikationssammanhang:

  • begäran - ny böneföreteelse skapas per HTTP-begäran
  • session - en ny bönefunktion skapas per HTTP-session
  • applikation - en ny ServletContext skapas per ServletContext
  • globalSession - en ny bönefunktion skapas per global session i Portlet-miljön (i Servlet-miljön är det globala sessionens omfattning lika med sessionens omfattning)
  • websocket - en ny bönefunktion skapas per WebSocket-session

Ingen ytterligare installation krävs för att deklarera och få åtkomst till webbskopade bönor i Spring Web MVC-miljön.

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 (före våren 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 (efter våren 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();
    }
}

Komponenter med kommentarer

@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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow