Skip to content

16. Applicazione web MVC in un’architettura a tre livelli – Esempio 2

16.1. Introduction

Abbiamo scritto l’applicazione [personnes-01] con la seguente struttura:

Il livello [dao] implementava l’elenco delle persone gestito tramite un oggetto [ArrayList]. Questo ci ha permesso di non soffermarci sui livelli [dao] e [service] per concentrarci sul livello [web]. Desideriamo far evolvere l’applicazione verso un ambiente più realistico in cui l’elenco delle persone venga memorizzato in una tabella del database. Ciò ci porterà a modificare il livello [dao]. Ciò avrà un impatto sugli altri due livelli. Per sfruttare l’indipendenza dei livelli offerta da Spring IoC, riprenderemo l’applicazione [personnes-01] e la configureremo con Spring IoC:

La nuova applicazione si chiamerà [personnes-02]. Una volta sviluppata, sappiamo che potremo modificare i livelli [dao] e [service] senza apportare modifiche al codice del livello [web]. È proprio questo l’obiettivo che ci prefiggiamo.

Creiamo un nuovo progetto Eclipse [personnes-02] copiando e incollando il progetto [personnes-01], come spiegato al paragrafo 6.2:

In [1] compare il file di configurazione in cui definiremo i bean dei livelli [dao] e [service]. Il suo contenuto è il seguente:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- la classe DAO -->
    <bean id="dao" class="istia.st.mvc.personnes.dao.DaoImpl" init-method="init"/>
    <!-- la classe di servizio -->
    <bean id="service" class="istia.st.mvc.personnes.service.ServiceImpl">
        <property name="dao">
            <ref local="dao" />
        </property>
    </bean>
</beans>
  • riga 5: definisce il bean denominato [dao] come un'istanza della classe [DaoImpl]. Dopo l'istanziazione, viene eseguito il metodo [init] dell'istanza.
  • righe 7-10: definiscono il bean denominato [service] come un'istanza della classe [ServiceImpl].
  • righe 8-10: la proprietà [dao] dell’istanza [DaoImpl] viene inizializzata con il riferimento al livello [dao] creato alla riga 5. Ricordiamo che la classe [ServiceImpl] possiede effettivamente la proprietà [dao] e il relativo setter:
public class ServiceImpl implements IService {

     // il livello [dao]
    private IDao dao;

    public IDao getDao() {
        return dao;
    }

    public void setDao(IDao dao) {
        this.dao = dao;
    }
...

Ovviamente, questo file da solo non fa nulla. Il controller [Application] lo utilizzerà nel suo metodo [init] per istanziare il livello [service]. Ricordiamo la versione precedente del metodo [init] del controller:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
...
     // servizio
    ServiceImpl service = null;

     // inizializzazione
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
         // istanziazione del livello [dao]
        DaoImpl dao = new DaoImpl();
        dao.init();
         // istanza del livello [service]
        service = new ServiceImpl();
        service.setDao(dao);
    }

Alla riga 5, eravamo stati costretti a specificare esplicitamente il nome della classe di implementazione del livello [service] e alla riga 12 quello del livello [dao]. Con Spring IoC, il metodo [init] diventa il seguente:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
     // parametri di istanza
    ...

     // servizio
    private IService service = null;

     // inizializzazione
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
    ...
         // istanza del livello [service]
        service = (IService) new XmlBeanFactory(new ClassPathResource("spring-config.xml")).getBean("service");
    }
  • riga 7: il campo privato [service] non è più di tipo [ServiceImpl] ma di tipo [IService], c.a.d. del tipo dell'interfaccia del livello [service]. Il livello [web] non è quindi più legato a una particolare implementazione di tale interfaccia.
  • riga 14: inizializzazione del campo [service] a partire dal file di configurazione [spring-config.xml].

Queste sono le uniche modifiche da apportare. Integriamo questa nuova applicazione in Tomcat, avviamolo e poi richiediamo l’URL [http://localhost:8080/personnes-02]:

Image

16.2. Archiviazione dell’applicazione web

Abbiamo sviluppato un progetto Eclipse/Tomcat per un’applicazione a tre livelli:

In una versione futura, il gruppo di persone verrà inserito in una tabella del database.

  • Ciò comporterà una riscrittura del livello [dao]. Questo è facilmente comprensibile.
  • Anche il livello [service] verrà modificato. Attualmente, la sua unica funzione è quella di garantire un accesso sincronizzato ai dati gestiti dal livello [dao]. A tal fine, abbiamo sincronizzato tutti i metodi del livello [service]. Abbiamo spiegato perché questa sincronizzazione fosse collocata in questo livello piuttosto che nel livello [dao]. Nella nuova versione, il livello [service] avrà ancora l’unico ruolo di sincronizzazione degli accessi, ma questa sarà garantita da transazioni del database piuttosto che dalla sincronizzazione dei metodi Java.
  • Il livello [web] rimarrà invece invariato.

Per facilitare il passaggio da una versione all’altra, creiamo un nuovo progetto Eclipse [mvc-personnes-02B], copia del precedente progetto [mvc-personnes-02], ma in cui i livelli [web, service, dao, entites] sono stati inseriti in archivi .jar:

La cartella [src] ora contiene solo il file di configurazione Spring [spring-config.xml]. In precedenza conteneva anche il codice sorgente delle classi Java. Questi elementi sono scomparsi, sostituiti dalle loro versioni compilate inserite negli archivi [personnes-*.jar] mostrati in [1]:

Il progetto [mvc-personnes-02B] è stato configurato per includere gli archivi [personnes-*.jar ] nel proprio ClassPath.

Stiamo distribuendo il progetto web [mvc-personnes-02B] all’interno di Tomcat:

Per testare il progetto, avviamo Tomcat e poi accediamo all’URL [http://localhost:8080/personnes02B]:

Image

Il lettore è invitato a effettuare ulteriori test.

Nella versione con database, modificheremo i livelli [service] e [dao]. Vogliamo dimostrare che sarà quindi sufficiente sostituire nel progetto precedente gli archivi [personnes-dao.jar] e [personnes-service.jar] con i nuovi archivi affinché la nostra applicazione funzioni d’ora in poi con un database. Non sarà necessario modificare gli archivi del livello [web] e del livello [entites].