|
È molto più bello sapere qualcosa di tutto, che tutto di
una cosa
|
|
| Home Page |
|
| Articoli |
|
| News |
|
| Forum |
|
| Classi |
|
|
|
|
|
prima parte - Spring MVC, Inversione del Controllo e Dependency Injection
By
Massimo Cimino
22 maggio 2007
Valutazione Acquisita:
200
|
 |
|
In questo articolo, suddiviso in due parti, ci proponiamo di investigare alcune delle possibilità che ci offre uno dei framework più importanti nel mondo java : Spring. Nel corso dello svolgimento della prima parte parleremo del framework, della sua struttura e ci soffermeremo su alcuni dei concetti chiave che si ritrovano spesso applicati in Spring, come il concetto di Dependency Injection e di Inversione del Controllo. Nella seconda parte ci occuperemo della implementazione del paradigma MVC fornita con l'ultima distribuzione, presentando nello stesso tempo la implementazione di un caso d'uso didattico, consistente in una applicazione web che renderizza in una pagina JSP un ipotetico elenco di dipendenti di una azienda.
|
|
|
Il Framework
|
top
|
|
Spring è un framework creato per costruire applicazioni J2EE robuste, basato su una architettura a strati composta da sette differenti moduli.  Fig - Overview of the Spring Framework (by Spring Reference 2.0) - lo strato Core è la sua parte più importante e contiene le funzioni essenziali del framework. In questo layer vengono esposte la implementazione di Spring del principio della inversione del controllo.
- lo strato DAO è un layer di persistenza.
- lo strato AOP integra all’interno del framework le funzionalità tipiche della programmazione orientata agli aspetti.
- lo strato ORM consente di integrare all’interno delle applicazioni alcuni tra i più popolari tool per l’accesso ai database relazionali, come ad esempio Hibernate, iBatis ed altri ancora.
- lo strato WEB fornisce una implementazione del paradigma Model – View – Controller per le applicazioni web.
|
|
Inversion of Control – Dependency Injection
|
top
|
Ci si potrebbe chiedere cosa si intende in concreto quando si parla di inversion of control e qual'è la differenza tra IoC e Dependency Injection ? Spesso infatti questi due termini sono usati indifferentemente, come se fossero sinonimi, in realtà indicano concetti sottilmente distinti.
Per Inversion of control si intende una varietà di tecniche che fanno si che un oggetto diventi passivo all'interno di un sistema. Il che significa in altri termini che un framework che applica tecniche di inversione del controllo sottrae agli oggetti che sono calati al suo interno alcune delle loro responsabilità. La Dependency Injection è proprio una di queste tecniche. Essa prende il controllo su tutti gli aspetti di creazione degli oggetti e de delle loro dipendenze. Spring usa molto diffusamente la Dependency Injection con il risultato, tra le altre cose, di eliminare dal codice applicativo ogni logica di inizializzazione.
Vediamo adesso un semplice esempio di come una tecnica di Dependency Injection può migliorare la vita di una applicazione. Consideriamo il classico use case per la ricerca di qualcosa su uno storage e definiamo una interfaccia per la classe che eseguirà la ricerca:
public interface IFinder { public List search(Map searchParameters); }
avvalendosi della collaborazione di un oggetto Handler.
public interface Handler { public void buildQuery(Map parameters ); public List search(); }
di seguito la classe implementatrice per la ricerca su un db oracle.
public class OracleHandler implements Handler {
public void buildQuery(Map parameters) { [ ... ]
}
public List search() { [ ... ] }
}
Infine non resta che creare la classe di implementazione dell'interfaccia Finder .
public class BookFinder implements IFinder {
private Handler oracleHandler = new OracleHandler();
public List search(Map searchParameters) { oracleHandler.buildQuery(searchParameters); return oracleHandler.search(); }
}
Questa implementazione presenta almeno tre diverse problematiche. Intanto abbiamo un certo spreco di risorse dovuto al fatto che ogni istanza di BookFinder possiede una diversa istanza di OracleHandler. Inoltre c'è il fatto, molto più significativo, che la classe BookFinder ha una dipendenza per attributo dalla classe OracleHandler. Questo rappresenta a tutti gli effetti un indesiderato accoppiamento tra due classi che non dovrebbero conoscersi se non tramite le rispettive interfacce. Così come stanno le cose invece è molto probabile che un qualsiasi cambiamento della classe OracleHandler possa avere effetto sulla classe BookFinder. In più questo alto accoppiamento porta con se la conseguenza che la classe Finder è molto difficile da testare. Infatti risulta di fatto impossibile creare un test unitario che sia slegato dalla presenza di un server Oracle up and running mentre per definizione gli unit test dovrebbero poter essere eseguiti indipendentemente da ogni tipo di risorsa esterna alla classe testata.
|
|
DON'T CALL ME, I'LL CALL YOU
|
top
|
Come possiamo dunque evitare gli effetti nefasti del “tight coupling” ? Supponiamo per un momento che la classe BookFinder non debba più occuparsi di gestire la creazione dell'oggetto OracleHandler, ma che questo gli sia in qualche maniera “fornito” dal framework. Questo scenario rappresenta con esattezza il concetto di Dependency Injection. Vediamo come cambiano le cose.
In Spring abbiamo due tipi di Dependency Injection, la prima prende il nome di constructor based:
public class BookFinder implements IFinder {
private Handler handler ; public BookFinder (Handler h){ this.handler = h ; }
public List search(Map searchParameters) { handler.buildQuery(searchParameters); return handler.search(); }
}
La seconda si chima setter – based :
public class BookFinder implements IFinder {
private Handler handler ; public void setHandler(Handler h){ this.handler = h ; }
public List search(Map searchParameters) { handler.buildQuery(searchParameters); return handler.search(); }
}
In entrambi i casi la prima cosa che salta agli occhi è che non c'è più accoppiamento tra BookFinder e OracleHandler. Sarà Spring che si occuperà di ottenere un reference a OracleHandler e darlo alla classe BookFinder. Quest'ultima quindi obbedisce al principio : “non chiamarmi, ti chiamo io” anche noto come di principio Hollywood, in altri termini: non perdere tempo a chiedere le dipendenze è Spring che te le fornisce!
Un' ultima osservazione riguarda la testabilità di questa soluzione. La presenza di un metodo setter sulla classe BookFinder facilita di molto la gestione dei test con i mock object:
public void testSearch(){ Mock mock = mock(Handler.class); Handler mockHandler = (Handler)mock.proxy(); bookFinder.setHandler(mockHandler); [ ... ] }
|
|
Spring IoC Container – BeanFactory e ApplicationContext
|
top
|
In questa parte del tutorial cerchiamo di capire il funzionamento del cuore di Spring : il suo IoC container. Come abbiamo visto l’interfaccia BeanFactory è la rappresentazione del conteiner di Spring. Il suo compito fondamentale è quello della creazione e della inizializzazione degli oggetti applicativi, e il collegamento di questi ultimi con le loro dipendenze. Al di sopra di BeanFactory abbiamo un altro oggetto molto importante: ApplicationContext. Quest’ultima è una estensione di BeanFactory e aggiunge caratteristiche legate all’integrazione con AOP, internazionalizzazione, propagazione di eventi ed altro ancora.
Normalmente BeanFactory e le sue specializzazioni vengono configurate per via di file XML. Di seguito un esempio di come appare la struttura di un file di configurazione :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> </beans>
E questo è un esempio tipico di come si istanzia un container e si ottiene un bean :
… Resource res = new ClassPathResource("spring.xml"); BeanFactory factory = new XmlBeanFactory(res); myBusinessObject = (MyBusinessObject)factory.getBean("theBeanName"); myBusinessObject.doSomeWork(); …
Uno degli aspetti su cui vale la pena soffermarsi leggengo queste poche righe di codice è che non esiste in Spring alcuna restrizione sugli oggetti applicativi : sono semplici POJO. Ed è proprio questo ciò che si intende quando si dice che Spring è un framework “lightweight”. Spring non si intromette ne impone vincoli di alcun tipo sugli oggetti di business delle applicazioni, anche quando si parla di applicazioni web.
Non c’è alcuna necessità per esempio di far estendere ai propri oggetti applicativi classi astratte del framework, essi saranno liberi di estendere unicamente le classi che hanno senso nel dominio degli oggetti di business. Questo permette al designer di concentrarsi unicamente sulla propria business logic, e di progettare con piena libertà di seguire tutti i principi della Object Orientation e di applicare quando lo si ritiene necessario i design pattern, i principi e le best practices della programmazione orientata agli oggetti.

Fig - The Spring IoC container (by Spring Reference 2.0)
|
|
|

Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati sotto licenza Creative Commons
|
|
|