Introduzione
In un'applicazione, per migliorare quelle che sono le performance di risposta ad una richiesta di servizio, è utile, in genere, prendere in considerazione la possibilità di effettuare un salvataggio in memoria di una serie di dati (Value Object [VO]), che hanno determinate caratteristiche di variabilità (bassa dinamicità), e che hanno un'alta frequenza di utilizzo.
L'articolo propone un'implementazione di una cache, partendo dall'esperienza del pattern di CacheManagement [CM].
La variazione alla proposta originale, vuole garantire flessibilità nella gestione delle politiche di cache ed un alto grado di disaccoppiamento nei confronti dell'applicazione in cui si innesta.
E' altresì vero, che un'attenta progettazione delle applicazioni enterprice, secondo i pattern più consolidati della letteratura J2EE [J2EE] e secondo le nuove specifiche Ejb, può garantire prestazioni eccellenti, prescindendo da un componente di cache studiato ad hoc.
Contesto
Il componente che l'articolo propone, si inserisce nel contesto di un'applicazione già esistente, con un design già consolidato. In questo contesto il componente di cache si occupa di migliorare le performance di risposta ad alcune invocazioni, rendendo immediatamente disponibile l'oggetto di risposta alla richiesta, senza la necessità di elaborazioni ulteriori (chiamate remote, accesso a base di dati ed altro).
Intento
Il pattern realizza un tentativo di indirizzare il trattamento di oggetti che rappresentano i dati dell'applicazione, a cui il sistema accede con una certa frequenza e che hanno una variabilità temporale bassa. Tipicamente, si può pensare di conservare in una cache, i dati che rappresentano i comuni, le province, le regioni, oppure informazioni a bassa dinamicità legate alla struttura organizzativa, ed altro.
Motivazione
Il pattern disaccoppia l'effettiva implementazione dell'oggetto di cache, concentra in una classe la gestione delle politiche di caching, come il recupero della chiave per l'oggetto in cache, la valutazione dell'occupazione di memoria della cache, il rinfresco dei dati cached, e garantisce un'interfaccia unica e semplicemente integrabile nell'applicazione.
Struttura
Nella sua definizione originale [CM] il pattern ha la seguente rappresentazione:
l'idea è quella di offrire una semplice interfaccia per effettuare il caching delle informazioni utili.
Spiegazione del funzionamento
Il ciclo di vita del componente pone a cavallo del life cicle dell'applicazione un'istanza del CacheManager. L'invocazione viene fatta su tale istanza (fetchObejct(obj)) e si occupa di verificare se l'oggetto richiesto è presente nella Cache, oppure no. Se non è presente, si procede al reperimento dell'oggetto attraverso il normale ciclo di vita dell'applicazione.
Implementazione
Per garantire una migliore gestione di alcune caratteristiche del componente Cache ed inserirsi nel ciclo di vita di un framework già esistente, senza modificarne eccessivamente il funzionamento, si è proceduto ad una leggera modifica del pattern.
La variazione inserita offre la possibilità di dichiarare la classe CacheManager come una Topic ad una coda di messaging [JMS]. In generale si può vedere il CacheManager come un EventListener, che si mette in ascolto di eventi generati da una sorgente.
In tal modo le istanze di CacheManager che si registrano alla Topic potranno essere amministrate da un generatore di messaggi che funzionerà da administrator per la cache.
Inoltre disaccoppiare ulteriormente il mondo cache dal gestore di cache, permette di offrire diverse implementazioni di Cache in maniera trasparente all'utilizzatore.
L'interfaccia rimane unica e nello specifico si offre una cache locale (wrapper di una Hashtable) e una Cache distribuita, che registra gli oggetti presso il JNDI Server.
L'implementazione del CacheManager gestisce il reperimento dei dati da una cache locale (migliori performance di risposta), o alternativamente da una cache distribuita su JNDI Sever (disponibilità del dato su più tier ed in cluster). Inotre gestisce le politiche di abilitazione della cache, di refresh degli oggetti in cache, ed altro, ricevendo i comandi di amministrazione dal generatore di eventi (nell'esempio specifico un subscriber JMS).
Un caso d'uso
Il design proposto effettua una di cache di oggetti, in modo indipendente dall'applicazione con cui viene interfacciato. La gestione proposta del management delle politiche di cache, presuppone la presenza di un coda JMS. In pratica una minima variazione al codice del CacheManager, lo rende indipendente da questo vincolo, e si può far pilotare il CacheManager da un Generatore di Eventi generico.
Per contestualizzare l'uso del componente, si riporta come caso d'uso del CacheManager l'applicazione MokaPattern [MP]. In questo contesto, il componente di cache si pone a cavallo del request handler di richiesta dell'Account e memorizza l'Object Value che il business genera (AccountOM). Non è sicuramente l'oggetto migliore da inserire nella cache, perché ha delle caratteristiche di dinamicità elevate, ma l'esempio ha lo scopo di dimostrare la possibilità di utilizzo del componente in modo indipendente dall'applicazione sviluppata.
L'archiettura del prototipo si modifica in questo modo:
Esempio di codice estratto dall'hanlder:
public class AccountRequestHandler extends BaseRequestHandler {
...
public void execute(HttpServletRequest request, HttpServletResponse
response, ServletContext context)
throws ServiceException{
...
AccountOM model = null;
CacheManager chm = new CacheManager();
try{
//la chaive di ricerca e di memorizzazione è lo UserId
model= (AccountOM)chm.fetchObject(userid);
}
catch(NotFoundObjectException nfoe){
proxy =
MvcFactoryBusinessDelegate.getBusinessDelegate(this.getClass().getName(),
userid);
model = ((MvcBusinessDelegateImpl)proxy).getAccount();
chm.putObject(userid,model);
}
...
Per invocazioni successive il valore dell'AccountOM è immediatamente disponibile. Il CacheManager ne verifica la presenza nella cache e lo restituisce all'elaborazione.
Inoltre è interessante verificare l'operatività del Subscriber di amministrazione, che scatena l'evento di REFRESH, che rinfresca gli oggetti dalla Cache.
Il client invia un TextMessage (l'evento) alle varie istanze di CacheManager registrate in Topic, e nel metodo onMessage si processa l'evento.
public void onMessage(Message policyMsgEvent) {
try {
if (policyMsgEvent instanceof TextMessage) {
TextMessage txtMsg = (TextMessage) policyMsgEvent;
if (txtMsg.getText().trim().equalsIgnoreCase("DISABLE")) {
this.enable = false;
}
if (txtMsg.getText().trim().equalsIgnoreCase("ENABLE")) {
this.enable = true;
}
if (txtMsg.getText().trim().equalsIgnoreCase("REFRESH")) {
this.removeAll();
}
}
} catch (Exception e) {.... }
In questo caso, avendo rimosso l'oggetto dalla cache, il CacheManager rilancia una NotFoundObjectException e il ciclo di vita dell'applicazione prosegue normalmente, andando a recuperare sul business, l'object model richiesto.
Commenti
L'articolo ha messo in evidenza una possibilità di sviluppo della gestione della cache in un architettura distribuita. In quest'ottica una serie di verifiche potrebbero essere interessanti.
Si vuole stimolare l'attenzione del lettore su eventuali problematiche legate all'implementazione del JNDI Server e sulla gestione della cache in cluster, nonché l'ottimizzazione dell'amministrazione con la console JMS.
L'argomento è complesso e non del tutto affrontato dalla letteratura in genere. Il design J2EE dovrebbe prescindere da componenti di questo tipo, ma a volte risulta necessario giungere ad un compromesso che affronti la questione perfomance dell'applicazione.
Il codice d'esempio è scaricabile qui.
Bibliografia e riferimenti
- [VO] S.Rossini, L. Dozio - "J2EE Patterns - Il pattern value object", Mokabyte N.69 Dicembre 2002
- [CM] Mark Grand: Patterns in Java Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML, second edition
- [JMS] S.Rossini -- "Java Message Service - La gestione dei messaggi in Java II parte: la pratica", Mokabyte N.61 Marzo 2002
- [J2EE] Alur,Crupi,Malks: Core J2EE Patterns - Best Practices and Design Strategies
- [MP] S.Rossini, L. Dozio - "J2EE Patterns - Il pattern MVC", Mokabyte N.70 Gennaio 2003
