SeamFramework.orgCommunity Documentation
Finora si sono visti pochi esempi di annotazioni di tipi di scope. Gli scope di un Web Bean determinano il ciclo di vita del Web Bean. Lo scope determina anche quali client fanno riferimento a quali istanze di Web Bean. Secondo la specifica Web Bean, uno scope determina:
Quando una nuova istanza di un Web Bean con tale scope viene creata
Quando un'istanza esistente di un Web Bean con tale scope viene distrutta
Quali riferimenti iniettati puntano a istanze di un Web Bean con tale scope
Per esempio, se esiste un Web Bean con scope di sessione, CurrentUser
, tutti i Web Bean che vengono chiamati nel contesto della medesima HttpSession
vedranno la stessa istanza di CurrentUser
. Quest'istanza verrà automaticamente creata la prima volta che in tale sessione occorre CurrentUser
, e verrà distrutta automaticamente quando la sessione termina.
Web Bean fornisce un modello di contesto estensibile. E' possibile definire nuovi scope creando una nuova annotazione di un tipo di scope.
@Retention(RUNTIME)
@Target({TYPE, METHOD})
@ScopeType
public @interface ClusterScoped {}
Sicuramente questa è la parte facile del lavoro. Affinché questo tipo di scope sia utile, avremo bisogno di definire un oggetto Contesto
che implementi lo scope! Implementare un Contesto
è compito molto tecnico, inteso solo per lo sviluppo di framework.
Si può applicare un'annotazione con un tipo scope ad una classe di implementazione Web Bean per specificare lo scope del Web Bean:
@ClusterScoped
public class SecondLevelCache { ... }
Solitamente si userà uno degli scopi predefiniti di Web Beans.
Web Beans definisce quattro scope predefiniti:
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
Per un'applicazione web che impiega Web Beans:
qualsiasi richiesta servlet ha accesso a scope attivi di richiesta, sessione e applicazione e, in aggiunta
qualsiasi richiesta JSF ha accesso allo scope attivo di conversazione
Gli scope di richiesta ed applicazione sono pure attivi:
durante le invocazioni a metodi remoti EJB,
durante i timeout EJB,
durante la consegna dei messaggi a bean message-drive, e
durante invocazioni web service.
Se l'applicazione prova ad invocare un Web Bean con scope che non ha un contesto attivo, una ContextNotActiveException
viene lanciata a runtime dal manager Web Bean.
Tre dei quattro scope predefiniti dovrebbero essere estremamente familiari ad ogni sviluppatore Java EE, quindi non si procede oltre nella discussione. Uno degli scope è comunque nuovo.
Lo scope di conversazione di Web Beans è un pò come il tradizionale scope di sessione in cui viene mantenuto lo stato associato all'utente del sistema, e vengono create richiest multiple al server. Comunque, a differenza dello scope di sessione, lo scope di conversazione:
è demarcato esplicitamente dall'applicazione, e
mantiene lo stato associato ad un particolare tab del browser in un'applicazione JSF
Una conversazione rappresenta un task, un'unità di lavoro dal punto di vista dell'utente. Il contesto di conversazione mantiene uno stato associato all'utente che sta lavorando. Se l'utente sta facendo più cose contemporaneamente ci saranno più conversazioni.
Il contesto di conversazione è attivo durante ogni richiesta JSF. Comunque, la maggior parte delle conversazioni vengono distrutte alla fine della richiesta. Se una conversazione deve mantenere lo stato nel corso richieste multiple, deve esplicitamente essere promossa a conversazione long-running.
Web Beans fornisce un Web Bean predefinito per controllare il ciclo di vita delle conversazioni in un'applicazione JSF. QUesto Web Bean può essere ottenuto per iniezione:
@Current Conversation conversation;
Per promuovere a long-running la conversazione associata alla richiesta corrente, occorre chiamare il metodo begin()
dal codice dell'applicazione. Per schedulare la distruzione del contesto attuale della conversazione long-running, si chiami end()
.
Nel seguente esempio un Web Bean con scope di conversazione controlla la conversazione alla quale è associato:
@ConversationScoped @Stateful
public class OrderBuilder {
private Order order;
private @Current Conversation conversation;
private @PersistenceContext(type=EXTENDED) EntityManager em;
@Produces public Order getOrder() {
return order;
}
public Order createOrder() {
order = new Order();
conversation.begin();
return order;
}
public void addLineItem(Product product, int quantity) {
order.add( new LineItem(product, quantity) );
}
public void saveOrder(Order order) {
em.persist(order);
conversation.end();
}
@Remove
public void destroy() {}
}
Questo Web Bean è capace di controlla il proprio ciclo di vita attraverso l'uso della API Conversation
. Ma altri Web BEan hanno un ciclo di vita che dipende completamente da un altro oggetto.
Il contesto di conversazione viene automaticamente propagato con ogni richiesta JSF faces (invio di form JSF). Non si propaga in modo automatico con richiesta non-faces, per esempio, navigazione tramite un link.
E' possibile forzare la conversazione da propagare tramite richiesta non-faces attraverso l'inclusione di un identificatore univoco della conversazione come parametro di richiesta. La specifica Web Bean riserva un parametro di richiesta chiamato cid
per tale uso. L'identificatore univoco della conversazione può essere ottenuto dall'oggetto Conversation
, che ha il nome Web Beans conversation
.
Quindi il seguente link propaga la conversazione:
<a href="/addProduct.jsp?cid=#{conversation.id}" >Add Product</a >
Il manager Web Bean deve propagare le conversazioni attraverso i redirect, anche se la conversazione non è marcata long-running. Questo rende facile implementare il comune pattern POST-then-redirect, senza impiegare fragili costrutti quali oggetti "flash". In questo caso il manager Web Bean aggiunge automaticamente un parametro di richiesta all'URL di redirect.
Al manager Web Bean è permesso di distruggere una conversazione e tutto lo stato mantenuto nel contesto in qualsiasi momento al fine di preservare le risorse. Un'implementazione di un manager Web Bean eseguirà questo sulla base di un qualche timeout sebbene non sia richiesto dalla specifica Web Beans. Il timeout è il periodo di inattività prima che la conversazione venga distrutta.
L'oggetto Conversation
fornisce un metodo per impostare iltimeout. Questo è solo un suggerimento al manager Web Bean, che è libero di ignorare quest'impostazione.
conversation.setTimeout(timeoutInMillis);
In aggiunta ai quattro scope predefiniti, Web Bean fornisce il cosiddetto pseudo-scope dipendente. Questo è lo scope di default per un Web Bean che non dichiara esplicitamente un tipo di scope.
Per esempio questo Web Bean ha uno scope di tipo @Dependent
:
public class Calculator { ... }
Quando un punto di iniezione di un Web Bean risolve verso un Web Bean dipendente, viene creata una nuova istanza di Web Bean dipendente ogni volta che il primo Web Bean viene istanziato. Le istanze dei Web Beans dipendenti non vengono mai condivise tra Web Bean differenti o punti di iniezione differenti. Sono oggetti dipendenti di altre istanze Web Bean.
Istanze Web Bean dipendenti vengono distrutte quando viene distrutta l'istanza da cui dipendono.
Web Beans facilità l'ottenimento di un'istanza dipendente di una classe Java o bean EJB, anche se la classe o bean EJB sono già dichiarati come Web Bean con qualche altro tipo di scope.
L'annotazione predefinita di binding @New
consente la definizioneimplicita di un Web Bean dipendente in un punti di iniezione. Si supponga di dichiarare il seguentecampo iniettato:
@New Calculator calculator;
Allora viene implicitamente definito il Web Bean con scope @Dependent
, tipo di binding @New
, tipo di API Calculator
, classe di implementazione Calculator
e tipo di deploy @Standard
.
Questo è vero se Calculator
è già dichiarato con un tipo di scope differente, per esempio:
@ConversationScoped
public class Calculator { ... }
Quindi i seguenti attributi iniettati ricevono ciascuno un'istanza di Calculator
:
public class PaymentCalc {
@Current Calculator calculator;
@New Calculator newCalculator;
}
Il campo calculator
ha iniettata un'istanza con scope conversazionale di Calculator
. Il campo newCalculator
ha iniettata un nuova istanza di Calculator
, con ciclo di vita che è legato a PaymentCalc
.
Questa caratteristica è particolarmente utile con i metodi produttori, come si vedrà nel prossimo capitolo.