CERCA SITEMAP FEED RSS 1280
Ultimo aggiornamento: 30 Agosto 2009

Session bean stateful

I session bean stateful garantisco il mantenimento dello stato della comunicazione.
Il container EJB infatti fa in modo che l’invocazione di metodi da parte dello stesso client sia gestita sempre dalla stessa istanza del session bean.
Ciò naturalmente ha un costo, dal momento che ogni istanza deve infatti essere mantenuta in memoria fino alla successiva richiesta si ha infatti una notevole occupazione di memoria.
Per ovviare a questo problema EJB fa uso di una tecnica nota come passivazione che consiste nel trasferire in memoria secondaria quei session bean stateful che sono in attesa di una richiesta da parte del client da diverso tempo.
Una volta che il session bean di tipo stateful viene trasferito in memoria secondaria, si libera lo spazio per nuove istanze di session bean che possono gestire nuove richieste da parte dei client.
Se il session bean trasferito in memoria secondaria dovesse riceve ulteriori richieste allora viene riattivato e trasferito nuovamente in mamoria centrale.

L’implementazione di session bean di tipo stateful deve seguire alcune semplici regole:
  • le variabili utilizzate per mantenere lo stato della conversazione devono essere tipi primitivi o comunque oggetti che implementano l’interfaccia Serializable.
  • il metodo del bean che chiude lo scambio di dati col client e quindi dovrebbe comportare la deallocazione dell’istanza del session bean stateful dalla memoria deve essere marcato con l’annotazione @Remove.
  • i metodi che il container EJB dovrebbe invocare prima della fase di passivazione e dopo la fase di attivazione devono essere marcati con le annotazioni @PrePassivate e @PostActivate.
Naturalmente come nel caso di session bean di tipo stateless è possibile utilizzare le annotazione @PostContruct e @PreDestroy per annotare quei metodi che andrebbero invocati alla creazione e alla distruzione dell’istanza del session bean.
I session bean di tipo stateful vengono utilizzati per implementare quelle attività utente che si completano in più step nelle quali il risultato di uno step è funzione del risultato dello step precedente.
Per comprendere la differenza rispetto ai session bean di tipo stateless, supponiamo di voler implementare un EJB in grado di contare il numero di volte che l’utente richiede una determinata servlet all’interno di una sessione utente.
E’ evidente che questa semplice operazione non potrebbe essere implementata con un session bean di tipo stateless per il semplice fatto che dopo ogni invocazione del metodo conta() l’istanza del session bean verrebbe riposta nel pool e utilizzata successivamente per servire altre richieste.
I session bean di tipo stateful invece per la loro capacità di mantenere lo stato della comunicazione con il client possono essere utilizzati per implementare questa funzione.

Creazione di un session bean stateful

La creazione di un session bean stateful è analoga alla definizione di un session bean di tipo stateless e prevede la definizione di un’interfaccia di business e l’implementazione dell’interfaccia nel session bean.
Per quanto riguarda l’interfaccia di business questa è accessibile localmente (@Locale) o da remoto tramite RMI (@Remote) ma non è accessibile da web-services per il semplice fatto che i web service sono per definizione "senza stato". Nel nostro caso definiremo un’interfaccia locale perché il session bean sarà utilizzato all’interno di una servlet:
package miopackage;

import javax.ejb.Local;
   
@Local
public interface MiaIntSFSBLocal 
{
  public int conta();
}
Come vediamo, viene usata l’annotazione @Locala per definire l’interfaccia locale e questa espone il solo metodo conta() che restituisce un intero.
Per quanto riguarda l’implementazione del session bean stateful, questa deve prevedere un campo privato di tipo int che verrà utilizzato come contatore, dovrà implementare l’interfaccia e quindi il metodo conta() ed infine dovrà essere annotata con @Stateful.
package miopackage;
  
import javax.ejb.Stateful;
   
@Stateful
public class MioSFSB implements MiaIntSFSBLocal 
{
  private int contaa;

  public MioSFSB()
  {
    contaa=0;
  }
        
  @Override
  public int conta() 
  {
    return contaa++;
  }
}
Il session bean definito resta in memoria finchè non scade la sessione utente perché non abbiamo definito alcun metodo marcato con @Remove che invocato comporta la deallocazione dell’EJB dalla memoria.
Avremmo comunque potuto definire un metodo fine() da invocare per deallocare il bean:
@Remove
public void fine()
{
  ...
}
Ancora una volta per utilizzare il session bean all’interno della servlet è possibile usare l’annotazione @EJB e sfruttare la dependency injection:
package miopackageweb;
   
import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import miopackage.MiaIntSFSBLocal;
   
public class MiaServletSFSBLocal extends HttpServlet 
{
  private static final long serialVersionUID = 1L;
   
  @EJB
  private MiaIntSFSBLocal miobean;
           
  public MiaServletSFSBLocal() 
  {
  }
   
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
  {
    PrintWriter out = response.getWriter();
    out.println( "<html><body>"+miobean.conta()+"</body></html>" );
    out.close();
  }
   
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
  {
  }
}

Ciclo di vita di un session bean stateful

A causa della passivazione, il ciclo di vita di un session bean stateful risulta più complesso di quello di un session bean stateless.

Nella gestione di un session bean stateful il container EJB svolge le seguenti operazioni:
  • crea un’istanza del bean usando il costruttore di default quando è necessario
  • memorizza l’istanza in memoria
  • esegue il metodo invocato dal client attraverso l’interfaccia di business
  • attende successive richieste da parte del client
  • se il periodo di attesa inizia ad essere troppo lungo, il container effettua la passivazione dell’istanza, spostandola fuori dalla memoria, serializzandola e memorizzandola in un memoria secondaria
  • se il client effettua una richiesta il bean viene riattivato (ricaricato in memoria dalla memoria temporanea)
  • se il client non invoca il bean per un periodo sufficientemente lungo il bean viene distrutto
  • se il client richiede la rimozione del bean questo viene prima attivato e quindi rimosso.
Come un session bean di tipo stateless, il session bean stateful ha quindi un proprio ciclo di vita ed è possibile specificare quali metodi devono essere invocati nel passaggio da una fase all’altra dello stesso.
Per farlo si fa uso delle annotazioni @PostContruct e @PreDestroy viste per i session bean stateless, alle quali si aggiungono le annotazioni @PrePassivate e @PostActivate che sono di esclusivo utilizzo di session bean stateful.
Tipicamente le operazioni compiute nei metodi annotati con @PostConstruct e @PostActivate sono le stesse e comportano l’allocazione di risorse, così come sono le stesse quelle compiute dai metodi annotati con @PreDestroy e @PrePassivate che comportano il rilascio di risorse. E’ possibile pertanto semplificare la definizione di metodi usando più annotazioni:
@PrePassivate
@PreDestroy
public void rilascio() 
{
  ...
}

@PostConstruct
@PostActivate
public void inzializzazione() 
{
  ...
}