Szukaj…


Luneta Singleton

Jeśli komponent bean jest zdefiniowany w zakresie singleton, w kontenerze Spring będzie inicjowana tylko jedna instancja pojedynczego obiektu. Wszystkie żądania do tego komponentu bean zwrócą tę samą udostępnioną instancję. Jest to domyślny zakres podczas definiowania komponentu bean.

Biorąc pod uwagę następującą klasę 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;
    }
}

Możemy zdefiniować singleton bean z adnotacją @Bean:

@Configuration
public class SingletonConfiguration {

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

Poniższy przykład dwukrotnie pobiera tę samą fasolę z kontekstu wiosennego:

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

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

Podczas rejestrowania właściwości singletonBean2 zostanie wyświetlony komunikat „zmieniona właściwość” , ponieważ właśnie pobraliśmy tę samą udostępnioną instancję.

Ponieważ instancja jest współużytkowana przez różne komponenty, zaleca się zdefiniowanie zakresu singletonu dla obiektów bezstanowych.

Leniwa fasola singleton

Domyślnie ziarna singletonu są wstępnie tworzone. Dlatego instancja obiektu współużytkowanego zostanie utworzona podczas tworzenia kontenera Spring. Jeśli uruchomimy aplikację, pojawi się komunikat „Inicjowanie singletonu bean ...” .

Jeśli nie chcemy, aby instancja komponentu bean była wcześniej utworzona, możemy dodać adnotację @Lazy do definicji komponentu bean. Zapobiegnie to utworzeniu fasoli, dopóki nie zostanie po raz pierwszy zażądane.

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

Teraz, jeśli uruchomimy kontener Spring, nie pojawi się komunikat „Inicjowanie leniwego singletona bean ...” . Fasola nie zostanie utworzona, dopóki nie zostanie zażądana po raz pierwszy:

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

Jeśli uruchomimy aplikację ze zdefiniowanymi fasolami singleton i leniwy singleton, wygeneruje następujące komunikaty:

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

Zakres prototypowy

Prototypowa fasola nie jest wstępnie tworzona podczas uruchamiania kontenera Spring. Zamiast tego nowa świeża instancja zostanie utworzona za każdym razem, gdy żądanie odzyskania tej fasoli zostanie wysłane do kontenera. Ten zakres jest zalecany dla obiektów stanowych, ponieważ jego stan nie będzie współdzielony przez inne komponenty.

Aby zdefiniować komponent bean o zasięgu prototypowym, musimy dodać adnotację @Scope, określającą pożądany typ zakresu.

Biorąc pod uwagę następującą klasę 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;
    }
}

Definiujemy definicję fasoli, określając jej zakres jako prototyp:

@Configuration
public class PrototypeConfiguration {

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

Aby zobaczyć, jak to działa, pobieramy fasolę z kontenera Spring i ustawiamy inną wartość dla jej pola właściwości. Następnie ponownie pobierzemy fasolę z pojemnika i sprawdzimy jej wartość:

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

Patrząc na następujący wynik, możemy zobaczyć, jak utworzono nowe wystąpienie dla każdego żądania komponentu bean:

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

Częstym błędem jest założenie, że fasola jest odtwarzana przy każdym wywołaniu lub wątku, NIE jest to przypadek. Zamiast tego tworzona jest instancja NA WTRYSK (lub pobieranie z kontekstu). Jeśli fasola o zasięgu prototypowym zostanie wstrzyknięta tylko do jednej fasoli singletonowej, będzie tylko jedna instancja tej fasoli o zakresie prototypu.

Spring nie zarządza całym cyklem życia prototypowego komponentu bean: kontener tworzy instancję, konfiguruje, ozdabia i w inny sposób montuje prototypowy obiekt, przekazuje go klientowi, a następnie nie ma dalszej wiedzy na temat tego prototypowego wystąpienia.

Dodatkowe zakresy w kontekstach uwzględniających sieć

Istnieje kilka zakresów, które są dostępne tylko w kontekście aplikacji obsługującej sieć:

  • request - dla każdego żądania HTTP tworzona jest nowa instancja komponentu bean
  • session - dla każdej sesji HTTP tworzona jest nowa instancja komponentu bean
  • application - tworzona jest nowa instancja ServletContext bean dla każdego ServletContext
  • globalSession - nowa instancja komponentu bean jest tworzona dla każdej sesji globalnej w środowisku portletu (w środowisku serwletu zakres sesji globalnej jest równy zakresowi sesji)
  • websocket - dla każdej sesji WebSocket tworzona jest nowa instancja komponentu bean

Żadna dodatkowa konfiguracja nie jest wymagana do deklarowania i uzyskiwania dostępu do fasoli o zasięgu sieciowym w środowisku Spring Web MVC.

Konfiguracja XML

<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"/>

Konfiguracja Java (przed wersją 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();
    }
}

Konfiguracja Java (po 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();
    }
}

Komponenty oparte na adnotacjach

@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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow