spring
Scopi di fagioli
Ricerca…
Ambito Singleton
Se un bean è definito con scope singleton, ci sarà una sola istanza di oggetto inizializzata nel container Spring. Tutte le richieste a questo bean restituiranno la stessa istanza condivisa. Questo è l'ambito predefinito quando si definisce un bean.
Data la seguente classe 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;
}
}
Possiamo definire un bean singleton con l'annotazione @Bean:
@Configuration
public class SingletonConfiguration {
@Bean
public MyBean singletonBean() {
return new MyBean("singleton");
}
}
L'esempio seguente recupera lo stesso bean due volte dal contesto Spring:
MyBean singletonBean1 = context.getBean("singletonBean", MyBean.class);
singletonBean1.setProperty("changed property");
MyBean singletonBean2 = context.getBean("singletonBean", MyBean.class);
Quando si registra la proprietà singletonBean2, verrà visualizzato il messaggio "proprietà modificata" , poiché è stata appena recuperata la stessa istanza condivisa.
Poiché l'istanza è condivisa tra diversi componenti, si consiglia di definire l'ambito Singleton per gli oggetti stateless.
Fagioli singleton pigri
Per impostazione predefinita, i bean singleton sono pre-istanziati. Quindi, l'istanza dell'oggetto condiviso verrà creata quando viene creato il contenitore Spring. Se avvieremo l'applicazione, verrà visualizzato il messaggio "Inizializzazione del bean singleton ..." .
Se non vogliamo che il bean sia pre-istanziato, possiamo aggiungere l'annotazione @Lazy alla definizione del bean. Ciò impedirà la creazione del bean fino a quando non viene richiesto per la prima volta.
@Bean
@Lazy
public MyBean lazySingletonBean() {
return new MyBean("lazy singleton");
}
Ora, se iniziamo il contenitore Spring, non apparirà il messaggio "Initializing lazy singleton bean ..." . Il bean non verrà creato fino a quando non viene richiesto per la prima volta:
logger.info("Retrieving lazy singleton bean...");
context.getBean("lazySingletonBean");
Se eseguiamo l'applicazione con entrambi i bean singleton e pigri definiti, produrrà i seguenti messaggi:
Initializing singleton bean...
Retrieving lazy singleton bean...
Initializing lazy singleton bean...
Prototipo di ambito
Un bean con ambito prototipo non è pre-creato all'avvio del contenitore Spring. Invece, verrà creata una nuova nuova istanza ogni volta che una richiesta per recuperare questo bean viene inviata al contenitore. Questo ambito è consigliato per oggetti stateful, poiché il suo stato non sarà condiviso da altri componenti.
Per definire un bean con scope prototipo, dobbiamo aggiungere l'annotazione @Scope, specificando il tipo di ambito che vogliamo.
Data la seguente classe 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;
}
}
Definiamo una definizione di bean, dichiarandone l'ambito come prototipo:
@Configuration
public class PrototypeConfiguration {
@Bean
@Scope("prototype")
public MyBean prototypeBean() {
return new MyBean("prototype");
}
}
Per vedere come funziona, recuperiamo il bean dal contenitore Spring e impostiamo un valore diverso per il suo campo proprietà. Successivamente, recupereremo nuovamente il bean dal contenitore e cercheremo il suo valore:
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());
Osservando il seguente risultato, possiamo vedere come è stata creata una nuova istanza su ciascuna richiesta di bean:
Initializing prototype bean...
Initializing prototype bean...
Prototype bean 1 property: changed property
Prototype bean 2 property: prototype
Un errore comune è quello di supporre che il bean sia ricreato per invocazione o thread, questo NON è il caso. Invece viene creata un'istanza PER INJECTION (o recuperata dal contesto). Se un bean con ambito Prototype viene iniettato solo in un singolo bean singleton, ci sarà sempre un'istanza di quel bean con ambito Prototype.
Spring non gestisce il ciclo di vita completo di un bean prototipo: il contenitore crea un'istanza, configura, decora e altrimenti assembla un oggetto prototipo, lo consegna al client e quindi non ha più conoscenza dell'istanza di prototipo.
Ambiti aggiuntivi in contesti web-aware
Esistono diversi ambiti che sono disponibili solo in un contesto dell'applicazione compatibile con il Web:
- richiesta : viene creata una nuova istanza bean per richiesta HTTP
- sessione : viene creata una nuova istanza di bean per sessione HTTP
- applicazione : viene creata una nuova istanza di bean per
ServletContext
- globalSession : viene creata una nuova istanza bean per sessione globale in ambiente Portlet (in ambito Servlet l'ambito della sessione globale è uguale all'ambito della sessione)
- websocket : viene creata una nuova istanza di bean per sessione WebSocket
Non è richiesta alcuna configurazione aggiuntiva per dichiarare e accedere ai bean con ambito Web nell'ambiente MVC di Spring Web.
Configurazione 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"/>
Configurazione Java (precedente alla primavera 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();
}
}
Configurazione Java (dopo la primavera 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();
}
}
Componenti guidati dall'annotazione
@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 {
...
}