Quarto articolo su Web Beans, un insieme di servizi per Java EE nati per rendere più agevole lo sviluppo di applicazioni. Stavolta focalizzeremo l‘attenzione sul ciclo di vita di un Web Bean, analizzandone le varie fasi di creazione e distruzione e i diversi aspetti.
LifeCycle di un Web Bean
Come già accennato nel secondo articolo di questa serie, il lifecycle di un’istanza contextual di un bean è gestita dal context object relativo allo scope del bean. L’implementazione di Context collabora con il container tramite le interfacce javax.context.Context e javax.context.Contextual per la creazione e la distruzione delle istanze.
Tale meccanismo varia in base al tipo di bean. Può accadere che il container inietti una dependency o risolva un EL name ma non esista alcuna istanza di un dato bean nella cache del context object dello scope del bean; in tal caso, il context object stesso crea automaticamente una nuova istanza contestuale del bean. Quando un context viene distrutto è sempre il context object che automaticamente distrugge tutte le istanze associate a tale context. Sia per la creazione che per la distruzione di istanze di bean il context object invoca operazioni definite nell’interfaccia Contextual. Questa definisce le operazioni di creazione e distruzione di istanze contextual di un dato tipo:
public interface Contextual { public T create(CreationalContext creationalContext); public void destroy(T instance); }
Una implementazione di Contextual è chiamata contextual type. L’interfaccia javax.context.CreationalContext deinisce il metodo push()
public interface CreationalContext { void push(T incompleteInstance); }
il quale consente al create() di Contextual di registrare una istanza contextual non completamente inizializzata. Un’istanza contextual viene considerata non completamente inizializzata fino a quando il metodo create() non ne restituisce l’istanza vera e propria. L’implementazione di Contextual non richiede obbligatoriamente l’invocazione del metodo push(); però, nel caso di bean con normal scope, l’invocazione è utile per minimizzare il ricorso del container a client proxy object in fase di creazione di istanze e di injection.
Il metodo create() esegue questi step:
- ottiene un’istanza di un bean;
- crea l’insieme di interceptor e di decorator e li associa all’istanza;
- inietta le dipendenze;
- imposta tutti i valori iniziali definiti nell’XML descriptor;
- se necessario, invoca il metodo @PostConstruct.
Se, nella fase di creazione di una istanza, si verifica una eccezione, il metodo create() la incapsula in una eccezione di tipo javax.inject.CreationException e ne scatena una di quest’ultimo tipo.
Il metodo destroy() esegue invece i seguenti step:
- se necessario, invoca il metodo di eliminazione;
- se necessario, invoca il metodo @PreDestroy;
- distrugge tutti gli oggetti dipendenti dall’istanza da distruggere.
In caso di eccezione in fase di distruzione di una istanza, il metodo destroy() la restituisce senza incapsularla in una eccezione più generica.
Lifecycle di simple bean
Vediamo più in dettaglio come viene gestito il lifecycle di alcuni tipi di bean partendo dai simple bean. Una classe Java può essere un “simple bean” se soddisfa i seguenti requisiti:
- non è di un type parametrizzato;
- non è una non-static inner class;
- è una classe concreta oppure è annotata con @Decorator;
- non è annotata con @Entity di JPA;
- non è annotata con le annotation per la definizione dei componenti di EJB;
- non implementa alcuna fra le interfacce javax.servlet.Servlet, javax.servlet.Filter, javax.servlet.ServletContextListener, javax.servlet.http.HttpSessionListener, javax.servlet.ServletRequestListener e javax.ejb.EnterpriseBean;
- non estende javax.faces.component.UIComponent;
- non è dichiarata come EJB bean;
- non è dichiarata come JPA entity;
- ha un costruttore che non accetta parametri in ingresso oppure annotato con @Initializer.
Nel momento in cui viene invocato il metodo create() di un Bean object che rappresenta un simple bean, per prima cosa il container invoca il costruttore del bean per ottenerne un’istanza. Il container passa a ciascun parametro in ingresso al costruttore l’oggetto restituito da javax.inject.manager.Manager.getInstanceToInject().
Successivamente il container inizializza i valori di ciascun attributo annotato con @EJB, @PersistenceContext o @Resource. A seguire inizializza i valori di tutti i field iniettati. Il container imposta il valore di ciascun field iniettato con l’oggetto restituito da javax.inject.manager.Manager.getInstanceToInject().
Quindi inizializza i valori di tutti i field i cui valori iniziali sono stati specificati nel file bean.xml. A questo punto invoca tutti i metodi di inizializzazione passando loro gli oggetti restituiti da javax.inject.manager.Manager.getInstanceToInject() come parametri d’ingresso. Infine crea l’insieme di interceptor e decorator e li associa all’istanza ed invoca, se necessario, il metodo @PostContruct.
Nel momento in cui invece viene invocato il metodo destroy() per un simple bean, il container prima invoca, se necessario, il metodo @PreDestroy e quindi distrugge tutti gli oggetti che dipendono dall’istanza da distruggere.
Lifecycle di una Servlet
Il container deve eseguire la dependency injection su ogni Servlet che viene istanziata. Ogni volta che il Servlet container crea una nuova istanza di Servlet, il WebBeans container deve eseguire i seguenti step:
- per prima cosa inizializza i valori di tutti i field che vengono iniettati. Ciascuno di questi campi viene impostato con l’oggetto corrispondente restiuito da javax.inject.manager.Manager.getInstanceToInject();
- successivamente invoca tutti i metodi di inizializzazione. A ciascun parametro in ingresso a un metodo viene passato l’oggetto restituito da javax.inject.manager.Manager.getInstanceToInject().
Quando il Servlet container distrugge una Servlet, il WebBeans container distrugge tutti gli oggetti da essa dipendenti.
Conclusioni
Creazione e distruzione vanno a costituire le fasi del ciclo di vita di un Web Bean: sono aspetti relativamente semplici da gestire, ma occorre conoscerne tutti gli aspetti che, brevemente, abbiamo illustrato. Dopo aver visto come viene gestito il lifecycle dei Web Beans, nel prossimo articolo tratteremo della gestione degli eventi.
Riferimenti
[1] JSR-299 Expert Group, “JSR-299: Context and Dependency Injection for Java”
Guglielmo Iozzia si è Laureato nel 1999 in Ingegneria Elettronica (indirizzo Biomedico) presso l‘Università di Bologna. Ha progettato e realizzato un software diagnostico per la predizione dell‘andamento della pressione intracranica in pazienti in terapia intensiva neurochirurgica. Frequenta il mondo Java dall‘inizio del 2000. Dopo numerose esperienze presso un‘azienda di Bologna del settore IT (fino all‘aprile del 2006), e per qualche mese in una analoga società di Roma, ha scelto la libera professione, lavorando per RAI Net fino ai primi mesi del 2008. In seguito è diventato Senior IT Consultant per la FAO (Food and Agriculture Organization of the United Nations). In ambito FAO ha dedicato quasi tutto il 2012 al progetto GRMS (Global Resources Management System) in qualità di "Web Services and cross-environmental integration specialist". Da luglio 2013 si è trasferito a Dublino, dove ricopre il ruolo di SVT Automation Engineer per IBM Ireland.