Concludiamo l‘analisi del business service layer illustrando come Spring possa interagire con lo strato di persistenza.
Introduzione
Con il presente articolo concludiamo la trattazione del business service layer implementato con il framework Spring approfondendo l’interazione dello stesso con lo strato di persistenza. Abbiamo già parlato dei benefici nell’uso di Spring come framework di implementazione dello strato di business e abbiamo visto come sia possibile costruire in modo molto semplice una architettura applicativa che preveda uno strato di business esposto allo strato di presentation esclusivamente mediante interfacce.
Analogamente è possibile integrare con la stessa filosofia lo strato di persistenza, che nella discussione che segue supporremo realizzato con Hibernate in coerenza a quanto fino ad ora visto nella serie. Vedremo come Spring metta a disposizione tutti gli strumenti necessari per realizzare questa integrazione in modo coerente ai principi del pattern IoC e in modo come sempre estremamente semplice per lo sviluppatore. Scrivere codice di persistenza utilizzando le librerie di supporto di Spring semplifica notevolmente il compito dello sviluppatore e conduce alla scrittura di codice estremamente conciso, privo di istruzioni ridondanti e semplice da manutenere.
Spring e il layer di persistenza
Spring fornisce classi di supporto che consentono di semplificare la scrittura del codice di accesso ai dati e di sfruttare le caratteristiche del container IoC indipendentemente dalla soluzione scelta per implementare lo strato di persistenza. Sia che si utilizzi per l’implementazione il puro e semplice JDBC che un framework ORM come Hibernate, Spring mette a disposizione classi di supporto e classi template che semplificano di gran lunga la scrittura dei DAO. Sfruttando le caratteristiche del container IoC inoltre tutte le dipendenze tra gli oggetti di business e i DAO vengono settate dal container e configurate all’esterno del codice senza la necessità di codice applicativo dedicato.
Nel nostro caso la scelta per l’implementazione dello strato di persistenza è caduta su Hibernate, l’ormai arcinoto framework ORM, ma la trattazione sarebbe assolutamente analoga nel caso si scegliesse una diversa soluzione implementativa.
Spring mette a disposizione classi DAO astratte per le varie tecnologie di accesso ai dati, come JDBC e Hibernate, ma anche ad esempio JDO, che possono essere estese dalle classi DAO del progetto che possono così sfruttare una serie di metodi standard che facilitano la scrittura del codice di persistenza.
Nel caso di Hibernate questa classe è la HibernateDAOSupport che diventa la superclasse di tutti i DAO della nostra applicazione. A questa classe deve essere fornito un riferimento a una SessionFactory operazione che ovviamente viene assolta dal container IoC mediante la definizione di un bean di tipo
org.springframework.orm.hibernate.LocalSessionFactoryBean
A sua volta la SessionFactory, che ci consentirà di acquisire sessioni per interagire con Hibernate, deve avere un riferimento a un data source per l’accesso al database dell’applicazione. Facendo l’ipotesi di utilizzare un JNDI data source, Spring mette a disposizione la classe
org.springframework.jndi.JndiObjectFactoryBean
Nell’esempio che segue è mostrato un tipico file di configurazione del container di Spring che mostra come tutti gli oggetti che hanno a che fare con lo strato di persistenza e le loro dipendenze vengono definiti completamente dal container stesso. Viene definito un bean dataSource il cui riferimento è iniettato nel bean sessionFactory che come proprietà prevede quanto in genere configurato nel file di proprietà di Hibernate. Tra queste vi è la lista dei file per il mapping tra oggetti persistenti e tabelle del database.
"http://www.springframework.org/dtd/spring-beans.dtd"> <!—Definzione datasource --> class="org.springframework.jndi.JndiObjectFactoryBean"> java:comp/env/jdbc/dbmoka class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> it/mokabyte/api/User.hbm.xml net.sf.hibernate.dialect.HSQLDialect
A questo punto una volta creati i vari oggetti necessari all’interazione con Hibernate, non resta che iniettare le dipendenze nei DAO e negli oggetti di business che utilizzano i DAO stessi. Dovrebbe quindi risultare finalmente chiaro quanto si era visto nel precedente articolo [4] riguardo la definizione del DAO e dell’oggetto di business di esempio:
L’oggetto del business service layer, il bean “service”, ha visibilità esclusivamente dell’interfaccia DAO , la cui implementazione è definita nel file di configurazione di Spring mentre nel DAO viene iniettata la dipendenza alla sessionFactory.
Supponendo di realizzare un DAO per accedere ad una ipotetica tabella utenti denominata USER, questo avrebbe una struttura simile:
package it.mokabyte.api.dao.hibernate; // imports... public class HibernateDAOImpl extends HibernateDaoSupport implements DAOInterface { public List getUsers() { return getHibernateTemplate().find("from USER"); } public User getUser(Long id) { return (User) getHibernateTemplate().get(User.class, id); } }
Si è ipotizzato che il nostro DAO implementi una interfaccia che preveda un metodo per reperire tutti gli utenti dalla nostra tabella (getUsers()) e un metodo per reperire i dati di un singolo utente a partire da un codice identificativo univoco dello stesso (getUser(Long id)).
Come si vede il DAO implementa i metodi dell’interfaccia ed estende la classe astratta di supporto che fornisce il metodo getHibernateTemplate() che restituisce una istanza di HibernateTemplate una classe helper che facilita la scrittura del codice di persistenza e wrappa le eccezioni di Hibernate nella gerarchia standard di eccezioni di Spring, indipendenti dalla tecnologia di implementazione dello strato di persistenza.
È facile notare come la struttura del DAO, già di per se’ semplificata con il solo uso di Hibernate, diventi ancora più semplice con l’utilizzo delle classi di supporto di Spring che nascondono tutta la gestione degli oggetti di Hibernate.
Come già detto il business service layer è assolutamente agnostico rispetto all’implementazione dello strato di persistenza in quanto ha un riferimento esclusivamente all’interfaccia DAO.
La classe dello strato di business avrà quindi la seguente struttura:
package it.mokabyte.api.service.impl; //imports... public class ServiceInterfaceImpl implements ServiceInterface { private DAOInterface dao; public void setDAOInterface(DAOInterface dao) { this.dao = dao; } public List getUsers() { return dao.getUsers(); } public User getUser(String userId) { User user = dao.getUser(Long.valueOf(userId)); return user; } }
Si noti il metodo setter che serve al container per iniettare la dipendenza al DAO e come nella classe non vi sia alcune riferimento alla tecnologia di implementazione dello strato di persistenza che è esposto allo strato di business solo mediante un’interfaccia.
Ciò rende gli oggetti di business realmente riusabili e indipendenti dallo strato di persistenza e conduce al risultato che avevamo annunciato nell’introduzione dell’articolo.
L’esempio mostrato è ovviamente una semplificazione in quanto non sempre esiste una relazione uno a uno tra un oggetto di business e un DAO, ma tutto quanto visto resta assolutamente valido anche in scenari molto più complessi.
Conclusioni
Nel presente articolo abbiamo mostrato come sia possibile utilizzare le classi di supporto di Spring per realizzare uno strato di business service layer realmente indipendente dalla tecnologia implementativa dello strato di persistenza. Non si è parlato della gestione delle transazioni in quanto è un argomento che meriterebbe una serie di articoli dedicati, soprattutto per ciò che riguarda la gestione dichiarativa che sfrutta le caratteristiche di Spring AOP, il modulo di Spring per la programmazione ad aspetti. Per chi fosse interessato a un approfondimento in tal senso si rimanda alla documentazione del framework [5]. Lo scopo degli articoli dedicati a Spring era piuttosto quello di mostrare come, utilizzando le caratteristiche del framework, sia possibile realizzare architetturalmente una applicazione con uno strato di business veramente riusabile e modulare che è visibile all’esterno solo mediante interfacce e che vede gli strati sottostanti allo stesso modo esclusivamente tramite interfacce in accordo ai migliori principi architetturali che prevedono un basso accoppiamento tra i layer applicativi. Tutto ciò può essere ottenuto senza grosso sforzo, con coerenza architetturale tra i vari componenti e con notevole semplicità da un punto di vista realizzativo, proprio come è stato illustrato.
Riferimenti
[1] Rod Johnson, “Expert one-on-one. J2EE Design and Development”, Wrox Press, 2002
[2] Rod Johnson – Juergen Holler, “Expert one-on-one. J2EE Development without EJB”, Wrox Press, 2004
[3] Rod Johnson, “Introduction to the Spring Framework 2.5”, TheServerSide.com, Ottobre 2007
[4] Alfredo Larotonda, “Il programmatore e le sue API – XIII Parte: Approfondiamo Spring”, Mokabyte 138, Marzo 2009
[5] Rod Johnson et al., “The Spring Framework. Reference Documentation – Chapter 9: Transaction Management”
Alfredo Larotonda, laureato in Ingegneria Elettronica, lavora da diversi anni nel settore IT. Dal 1999 si occupa di Java ed in particolare dello sviluppo di applicazioni web J2EE. Dopo diverse esperienze di disegno e sviluppo di applicazioni web per il mercato finanziario e industriale, si occupa ora in particolare di aspetti architetturali per progetti rivolti al mercato della pubblica amministrazione. È Sun Certified Enterprise Architect (SCEA) e ha inoltre conseguito le certificazioni SCJP, SCWCD 1.3, SCWCD 1.4, SCBCD.