Spring è un framework che ha come obiettivo principale quello di gestire la complessità nello sviluppo di applicazioni “enterprise” in ambiente Java. Nonostante la sua “giovane età” risulta un valido sostituto delle più classiche architetture EJB (Enterprise Java Beans). Questo articolo introduttivo è il primo di una serie che mira a trattare le sue principali funzionalità.
Introduzione
Tutta la storia di Java è costellata da tentativi più o meno riusciti di raggiungere la meta che è un po‘ nelle aspettative di tutti gli sviluppatori: programmare in modo semplice per componenti. Costruire le applicazioni come se si giocasse coi mattoncini del LEGO. Un tempo veniva pubblicizzata con ammirevole costanza la tecnologia JavaBeans, tuttora in auge, che prevede l‘utilizzo di semplici classi java (beans) con regole determinate di nomenclatura per la loro introspezione (proprietà accessibili mediante metodi prefissati da get e set). La costanza è stata inutile, in quanto i java beans sono rimasti confinati alla gestione di componenti visuali nelle interfacce utente e non hanno mai preso piede nella costruzione di applicazioni “enterprise” complete, essendo componenti troppo semplici per risolvere le problematiche più importanti. Successivamente l‘avvento della tecnologia EJB riprendeva il concetto di JavaBeans cercando di superarne i limiti. EJB mette a supporto dei java beans tutti i servizi di sistema attraverso un application server sottostando a dei contratti implementati tramite particolari interfacce e fornendo una serie di servizi in modo dichiarativo, attraverso specifici file di configurazione XML (deployment descriptors). La tecnologia EJB tuttavia, nonostante metta a disposizione un‘architettura a componenti evoluta, non è riuscita a portare semplicità nello sviluppo delle applicazioni enterprise. L‘utilizzo forzato delle interfacce di tipo home e remote rende il codice EJB largamente invasivo e lo sviluppo è appesantito dalla gestione dei deployment descriptors scritti in XML . I nuovi modelli di programmazione rappresentati dall‘Aspect Oriented Programming (AOP) e dall‘Inversion of Control (IoC) hanno aperto però nuove prospettive. Queste tecniche offrono alla vecchia tecnologia JavaBeans un modello dichiarativo simile a quello di EJB ma senza la sua complessità . Scrivere un semplice bean piuttosto che affidarsi alla complessità di un componente EJB permette allo sviluppatore di concentrarsi sugli aspetti logici dell‘applicazione. Spring fornisce una sua implementazione dell‘IoC e dell‘AOP e mette a disposizione un‘infrastruttura evoluta quanto quella EJB, senza le sue controindicazioni. In questo articolo introduttivo verrà fatto un cenno alle caratteristiche principali del framework che saranno poi trattate per esteso negli articoli successivi.
Il pattern Inversion of Control
Il pattern Inversion of Control sta alla base di Spring. Minimizzare le dipendenze fra gli oggetti significa rendere un‘applicazione più robusta, oltre a facilitare il riutilizzo dei componenti e rendere più semplice lo sviluppo. Normalmente un oggetto, per svolgere il compito per il quale è stato pensato, deve ricorrere alla “collaborazione” di altri oggetti, che possono essere sia oggetti locali che risorse esterne in un contesto distribuito. Per ottenere i servigi di un altro oggetto può operare in diversi modi: può istanziare quell‘oggetto e inizializzarlo attraverso un suo costruttore o attraverso dei metodi “set” appositi, oppure può ottenere quell‘oggetto da una “factory”, cioè un‘oggetto specializzato nel fornire istanze di altri oggetti , oppure ancora nel caso di risorse remote deve effettuare un “lookup”, per esempio attraverso un servizio come JNDI. In tutti questi casi l‘oggetto risulta in qualche modo “sporcato” da codice non propriamente specifico del flusso logico. Nel caso del componente recuperato da JNDI poi si crea una dipendenza forte con un servizio esterno che normalmente viene fornito da un Application Server. Nel primo caso descritto poi non è neanche sufficiente “nascondere” l‘oggetto “collaborante” dietro un‘interfaccia, perché al momento della sua istanziazione deve comunque esserne fornita un‘implementazione specifica. Il concetto alla base dell‘IoC è che le dipendenze degli oggetti devono essere risolte da una qualche infrastruttura esterna. Un oggetto riceve quindi automaticamente i riferimenti agli oggetti che collaborano con esso attraverso informazioni scritte in un qualche supporto, per esempio un file XML. L‘infrastruttura esterna cioè ha la responsabilità di istanziare gli oggetti e di fornire loro le relative dipendenze. Spring in particolare fornisce una classe BeanFactory che attraverso le informazioni lette da uno o più file di configurazione è in grado di fornire le istanze degli oggetti opportunamente inizializzate.
L‘Aspect Oriented Programming
Esistono caratteristiche di un sistema che sono logicamente indipendenti dal sistema stesso ma lo “invadono” in maniera capillare, come per esempio la security e gli aspetti transazionali. L‘AOP è un paradigma di programmazione che mira a disaccoppiare queste caratteristiche. In poche parole il concetto alla base di AOP è che il codice applicativo non deve essere nemmeno consapevole della loro esistenza. L‘AOP è definito da alcuni concetti chiave. Gli Aspects rappresentano per l‘appunto la modularizzazione delle caratteristiche indipendenti di un sistema, che altrimenti invaderebbero in modo “trasversale” l‘intera applicazione. il Join Point è un punto preciso durante la vita del programma, come per esempio l‘esecuzione di un metodo o la gestione di un‘eccezione; in Spring il Join Point rappresenta sempre l‘esecuzione di un metodo. Il Pointcut è un predicato che individua un insieme di Join Points, ossia, in concreto, un insieme definito per esempio da una tipica “regular expression”. Infine un Advice rappresenta un‘azione presa dall‘Aspect in un particolare Joinpoint, e normalmente i vari frameworks implementano un Advice come un “interceptor” o una catena di “interceptors” attorno a un particolare Join Point. Spring implementa questi concetti e fornisce un suo supporto specifico per l‘AOP.
Struttura modulare di Spring
Spring ha un a struttura modulare che poggia su uno strato principale, il Core Container, che rappresenta il supporto principale per tutti gli altri moduli, e altro non è che un‘implementazione del pattern IoC. La figura seguente chiarisce questa architettura, costituita da sette moduli ognuno dei quali gestisce una particolare problematica. È possibile utilizzare anche solo una parte di queste funzionalità , in base alle esigenze specifiche. Ciò è garantito dalle caratteristiche di “disaccoppiamento” permesse dall‘IoC e dall‘AOP. Integrare per esempio un tool di Object Relational Mapping utilizzando il modulo “O/R Mapping Module” significa lavorare quasi esclusivamente sugli aspetti di configurazione di Spring: le dipendenze nel codice applicativo si riducono all‘utilizzo all‘interno dei DAOs di specifiche classi “helper”, mentre i componenti di “business logic” non vengono minimamente “intaccati”.
Figura 1 – La struttura modulare di Spring
Il Core Container
Il Core Container fornisce l‘implementazione di Spring del pattern IoC principalmente attraverso la classe BeanFactory, che permette di separare le dipendenze dei componenti e gli aspetti di configurazione dal codice applicativo. La classe BeanFactory rappresenta insomma il “fattore esterno” che si occupa di iniettare le dipendenze nei componenti applicativi. In pratica la BeanFactory attraverso le informazioni lette da uno o più files xml o da altri supporti è in grado di fornire le istanze dei beans complete dei riferimenti agli oggetti che necessitano al bean stesso per l‘esecuzione della porzione di logica applicativa di cui sono responsabili.
L‘Application Module Context
Questo modulo attraverso la classe ApplicationContext estende le funzionalità del Core Module. Aggiunge il supporto all‘internazionalizzazione, eventi del ciclo di vita e la validazione. Oltre a questo fornisce una serie di servizi che permettono tra le altre cose l‘integrazione verso i servizi remoti, le architetture EJB, gli altri frameworks ecc.
Il modulo AOP
Spring fornisce la sua specifica implementazione dell‘AOP. Attraverso questo modulo è possibile utilizzare le caratteristiche di AOP in diversi contesti. Il modulo AOP, allo stesso modo del modulo
Core è utilizzato largamente anche da altri moduli; un esempio è la gestione della transazionalità dichiarativa.
Il modulo JDBC e DAO
Questo modulo permette di gestire il codice di accesso ai dati in modo pulito, evitando aperture e chiusure di connessioni e inoltre nasconde le eccezioni Jdbc in una propria gerarchia di eccezioni.
Offre anche il supporto alla transazionalità attraverso l‘utilizzo delle funzionalità di AOP.
Il modulo Object/Relational Mapping
L‘integrazione di un tool di ORM tramite questo modulo è semplificata enormemente. È sufficiente lavorare sulla configurazione e utilizzare delle specifiche classi “helper” nei propri DAOs. Sono gestiti tutti i principali tools ORM nell‘ambito dell‘open source, come Hibernate, JDO, iBatis ecc.
Il modulo Web
Il modulo Web estende l‘ApplicationContext, fornendo caratteristiche che sono appropriate per applicazioni di tipo web.
Il modulo MVC
Spring fornisce la sua implementazione del pattern MVC, anche se è in grado di integrare altri frameworks come Struts. L‘utilizzo dell‘IoC attraverso il modulo Core consente di separare la logica di controllo da quella di “business”. Spring fornisce diverse possibilità nella sua implementazione dell‘MVC, consentendo una certa flessibilità nella scelta delle soluzioni per specifici contesti.
Supporto per l‘integrazione
L‘integrazione verso altri frameworks come Struts, anche se non del tutto indolore, è garantita dalla struttura modulare di Spring. Esistono soluzioni specifiche per i più comuni frameworks open source. Il supporto per i servizi remoti, come per esempio i web services, permette di gestire l‘interazione con gli stessi sotto forma di semplici beans, nella filosofia consueta di Spring,. Nonostante il motivo principale insito nell‘utilizzo di Spring sia sostituire del tutto EJB, esiste un supporto specifico anche verso l‘integrazione con tali architetture. EJB comunque è un mondo che ha trovato una sua stabilità , è uno standard riconosciuto, e questo può rappresentare un valore non indifferente per le imprese. Poter trasportare in modo semplice le proprie applicazioni su queste architetture può costituire un‘arma in più.
I sottoprogetti Acegi Security e Spring Web Flow
I sottoprogetti Acegi Security e Spring Web Flow completano il quadro già ricco delle funzionalità offerte da Spring. Acegi utilizza l‘AOP e l‘IoC di Spring per gestire la security di un‘applicazione senza nessun impatto sul codice. Offre anche un supporto per il sistema di Single Sign On CAS (Central Authentication Service). Spring Web Flow invece è un motore di workflow orientato alle applicazioni web. Gli aspetti di workflow, ossia di gestione dei flussi applicativi, sono molto comuni nelle applicazioni web e Spring Web Flow rappresenta uno strumento evoluto ma relativamente semplice da utilizzare, e può anche sostituire del tutto il supporto MVC classico di Spring.
Conclusioni
Il framework Spring rappresenta al momento il tentativo più riuscito per semplificare lo sviluppo di applicazioni “enterprise” di una certa complessità nell‘ambito Java. Spring interpreta nel modo migliore i nuovi modelli di programmazione definiti dall‘IoC e dall‘AOP e permette di raggiungere un livello di disaccoppiamento degli strati applicativi impedito invece dalla natura “invasiva” della tecnologia EJB. L‘elenco dei servizi messo a disposizione copre tutte le problematiche classiche dello sviluppo applicativo e la semplicità del testing unitario ne fanno una piattaforma ideale per l‘utilizzo di metodologie agili come l‘Extreme Programming. Negli articoli successivi verranno trattate tutte le funzionalità principali del framework.
Riferimenti
[1] Spring Reference 2.0 http://www.springframework.org/
[2] Craig Walls – Ryan Breidenbach, “Spring in Action”, Manning, 2005