EJB3 Quale è la differenza tra Stateless vs Stateful?

0
2071

Nell’articolo di oggi come si capisce dal titolo andremo a vedere la differenza  tra Stateless vs Stateful negli EJB3.

Potremmo iniziare a  dire che gli ejb stateful mantengono lo stato e possono essere usati per il classico carrello della spesa mentre gli stateless, non avendo uno stato, possono essere usati per implementare dei servizi.

Ma siamo sicuri che la risposta è così semplice? Per quanto viene mantenuto lo stato di un ejb stateful? Per la durata della sessione web?

In questo post proveremo a fare un po più di chiarezza.

Le annotation degli ejb3

Una delle novità della versione 3 degli ejb  è il supporto alle annotation per i session bean ( la definizione degli ejb è stato trattato in un altro post vedi qui ).

Per definire un ejb è necessario scrivere un’interfaccia java e una classe che la implementa. L’interfaccia può essere annotata con @local o @remote: nel primo caso il nostro ejb sarà utilizzabile solo nella stessa jvm, nel secondo anche da jvm diverse (e quindi anche da altri server o cluster). La possibilità di definire ejb remoti è una delle feature più importanti ed è molto utile nella costruzione di architetture complesse.

La classe di implementazione di un ejb può essere annotata con @stateless @stateful, ora vediamo le differenze nel dettaglio.

Ma quindi quale è questa differenza?

Dopo tutta questa spiegazione torniamo all’argomento di questo post: quale è la differenza fra ejb stateful e stateless?

In entrambi i casi eseguendo un lookup jndi viene ritornato un oggetto stub e invocando un metodo su questo oggetto viene eseguito il corrispondente metodo su un ejb preso dal pool.

La differenza principale è proprio sulla scelta dell’ejb dal pool, se l’ejb è stateful si ha la sicurezza che tutte le chiamate a metodi di uno stub generano chiamate sullo stesso ejb. In pratica nel caso di ejb stateful lo stub mantiene un riferimento all’ejb utilizzato in modo da riusare sempre lo stesso oggetto, eventuali dati memorizzati come campi dell’oggetto sono mantenuti fra chiamate successive. Per questo motivo un ejb stateful non può essere riusato: una volta finito il proprio ciclo di vita viene distrutto dall’application server.

Se l’ejb è stateless viene utilizzato il primo ejb libero nel pool. In questo caso il pool è mantenuto essenzialmente per motivi di performance, semanticamente ogni volta che viene invocato un metodo su uno stub di un ejb stateless potrebbe essere creato un nuovo ejb su cui invocare il metodo. Per evitare la creazione di molti oggetti viene mantenuto un pool, quando viene invocato un metodo l’ejb viene rimosso dal pool e alla fine del metodo viene rimesso nel pool per essere utilizzato in futuro.

Un ejb stateless ha un ciclo di vita diverso rispetto a una Servlet (o a un bean di Spring singleton).

Una Servlet è creata una sola volta e lo stesso oggetto viene usato da più thread in parallelo, per questo non deve essere memorizzato niente nelle variabili di istanza di una servlet. Di un ejb stateless invece sono mantenute più istanze in contemporanea grazie al pool, ogni istanza viene usata sempre e solo da un thread alla volta. Per questo eventuali variabili di istanze di un ejb possono essere usati all’interno dei metodi, ovviamente tenendo conto del fatto che i dati saranno persi alla fine del metodo.

http://www.comptechdoc.org/docs/kanti/ejb/statefullsession.gif

Durata dello stato di un ejb stateful

Ma quindi quale è la durata dello stato di un ejb stateful? Possono essere usati per creare un carrello di un sito web di ecommerce? Dipende da dove viene memorizzato lo stub dell’ejb ritornato dalla chiamata jndi. Nel caso in cui lo stub è in una variabile locale di un metodo quando il metodo finisce lo stub si perde e un lookup jndi successivo comporta la creazione di un nuovo ejb. Nel caso in cui si voglia memorizzare il carrello in un ejb stateful è necessario salvare il riferimento allo stub nella sessione web. Ma quindi non è meglio memorizzare i dati del carrello direttamente nella sessione? Probabilmente sì, visto che la gestione degli ejb stateful è più pesante dal punto vista computazionale.

Il carrello in un ejb stateful può essere molto utile se accediamo al nostro sistema ecommerce sia da un sito web che da una applicazione desktop o da una applicazione mobile. In questo caso usando un ejb stateful possiamo scrivere la gestione del carrello una volta sola e usarlo nei vari ambienti, anche in quelli in cui non abbiamo la sessione web.

Un esempio da provare

Per concludere vediamo un esempio interessante: creiamo un ejb con un metodo solo e mettiamo un log (o un breakpoint se siamo in debug) nel costruttore dell’ejb e all’interno del metodo. Creiamo poi una servlet che esegue due volte un lookup jndi e due chiamate al metodo. Il metodo della servlet può essere schematizzato così:

1 MyEjb eb1 = eseguiLookup();
2 eb1.esegui();
3 eb1.esegui();
4 MyEjb eb2 = eseguiLookup();
5 eb2.esegui();
6 eb2.esegui();

Eseguendo questo codice quante volte viene invocato il costruttore dell’ejb nel caso che l’ejb sia definito con l’annotation stateful? La risposta corretta è 2, ogni volta che si effettua un lookup viene creato un nuovo ejb. Contenendo uno stato gli ejb stateful non vengono riciclati.

E nel caso di stateless quante volte viene invocato il costruttore? La risposta giusta non esiste! O meglio dipende da quante chiamate in parallelo alla Servlet vengono effettuate. Nel caso di una chiamata unica viene creato un ejb unico che ogni volta viene messo nel pool e subito riestratto. Nel caso di molte chiamate in parallelo questo codice potrebbe portare anche a 4 istanziazioni dell’ejb, dipende tutto dal numero di ejb presenti nel pool al momento della chiamata al metodo.