Skip to content

16. Aplicación web MVC en una arquitectura de tres capas – Ejemplo 2

16.1. Introducción

Hemos escrito la aplicación [personnes-01] con la siguiente estructura:

La capa [dao] implementaba la lista de personas gestionada mediante un objeto [ArrayList]. Esto nos ha permitido no detenernos en las capas [dao] y [service] para centrarnos en la capa [web]. Queremos hacer evolucionar la aplicación hacia un entorno más realista en el que la lista de personas se almacene en una tabla de una base de datos. Esto nos llevará a modificar la capa [dao], lo que afectará a las otras dos capas. Para aprovechar la independencia de las capas que ofrece Spring IoC, vamos a retomar la aplicación [personnes-01] y configurarla con Spring IoC:

La nueva aplicación se llamará [personnes-02]. Una vez que esté escrita, sabemos que podremos modificar las capas [dao] y [service] sin necesidad de cambiar el código de la capa [web]. Eso es precisamente lo que buscamos.

Creamos un nuevo proyecto de Eclipse, [personnes-02], copiando y pegando el proyecto [personnes-01], tal y como se ha explicado en el apartado 6.2:

En [1], aparece el archivo de configuración en el que vamos a definir los beans de las capas [dao] y [service]. Su contenido es el siguiente:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- la clase DAO -->
    <bean id="dao" class="istia.st.mvc.personnes.dao.DaoImpl" init-method="init"/>
    <!-- la clase de servicio -->
    <bean id="service" class="istia.st.mvc.personnes.service.ServiceImpl">
        <property name="dao">
            <ref local="dao" />
        </property>
    </bean>
</beans>
  • línea 5: define el bean denominado [dao] como una instancia de la clase [DaoImpl]. Tras la instanciación, se ejecuta el método [init] de la instancia.
  • Líneas 7-10: definen el bean denominado [service] como una instancia de la clase [ServiceImpl].
  • líneas 8-10: la propiedad [dao] de la instancia [DaoImpl] se inicializa con la referencia de la capa [dao] creada en la línea 5. Recordemos que la clase [ServiceImpl] sí tiene la propiedad [dao] y el setter correspondiente:
public class ServiceImpl implements IService {

    // la capa [dao]
    private IDao dao;

    public IDao getDao() {
        return dao;
    }

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

Por supuesto, este archivo por sí solo no hace nada. El controlador [Application] lo utilizará en su método [init] para instanciar la capa [service]. Recordemos la versión anterior del método [init] del controlador:

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

    // inicialización
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
...
        // instanciación de la capa [dao]
        DaoImpl dao = new DaoImpl();
        dao.init();
        // instanciación de la capa [service]
        service = new ServiceImpl();
        service.setDao(dao);
    }

En la línea 5, nos vimos obligados a nombrar explícitamente la clase de implementación de la capa [service] y, en la línea 12, la de la capa [dao]. Con Spring IoC, el método [init] queda así:

@SuppressWarnings("serial")
public class Application extends HttpServlet {
    // parámetros de instancia
    ...

    // servicio
    private IService service = null;

    // inicialización
    @SuppressWarnings("unchecked")
    public void init() throws ServletException {
    ...
        // instanciación de la capa [service]
        service = (IService) new XmlBeanFactory(new ClassPathResource("spring-config.xml")).getBean("service");
    }
  • línea 7: el campo privado [service] ya no es de tipo [ServiceImpl], sino de tipo [IService], c.a.d. del tipo de la interfaz de la capa [service]. Por lo tanto, la capa [web] ya no está vinculada a una implementación concreta de esta interfaz.
  • Línea 14: inicialización del campo [service] a partir del archivo de configuración [spring-config.xml].

Estas son las únicas modificaciones que hay que realizar. Integramos esta nueva aplicación en Tomcat, la iniciamos y, a continuación, accedemos a la URL [http://localhost:8080/personnes-02]:

Image

16.2. Archivado de la aplicación web

Hemos desarrollado un proyecto Eclipse/Tomcat de una aplicación de tres capas:

En una próxima versión, el grupo de personas se almacenará en una tabla de la base de datos.

  • Esto supondrá una reescritura de la capa [dao]. Esto es fácil de entender.
  • La capa [service] también se modificará. Actualmente, su única función es garantizar un acceso sincronizado a los datos gestionados por la capa [dao]. Con este fin, hemos sincronizado todos los métodos de la capa [service]. Ya hemos explicado por qué esta sincronización se situó en esta capa en lugar de en la capa [dao]. En la nueva versión, la capa [service] seguirá teniendo como única función la sincronización de los accesos, pero esta se llevará a cabo mediante transacciones de base de datos en lugar de mediante la sincronización de métodos Java.
  • La capa [web], por su parte, permanecerá sin cambios.

Para facilitar la transición de una versión a otra, creamos un nuevo proyecto Eclipse [mvc-personnes-02B], que es una copia del proyecto anterior [mvc-personnes-02], pero en el que las capas [web, service, dao, entites] se han guardado en archivos .jar:

La carpeta [src] ahora solo contiene el archivo de configuración de Spring [spring-config.xml]. Anteriormente también contenía el código fuente de las clases Java. Estos elementos han desaparecido, sustituidos por sus versiones compiladas, que se encuentran en los archivos [personnes-*.jar], tal y como se muestra en [1]:

El proyecto [mvc-personnes-02B] se ha configurado para incluir los archivos [personnes-*.jar ] en su ClassPath.

Implementamos el proyecto web [mvc-personnes-02B] en Tomcat:

Para probar el proyecto, iniciamos Tomcat y, a continuación, accedemos a la URL [http://localhost:8080/personnes02B]:

Image

Se invita al lector a realizar pruebas adicionales.

En la versión con base de datos, vamos a cambiar las capas [service] y [dao]. Queremos demostrar que bastará con sustituir en el proyecto anterior los archivos [personnes-dao.jar] y [personnes-service.jar] por los nuevos archivos para que nuestra aplicación funcione a partir de ahora con una base de datos. No tendremos que modificar los archivos de la capa [web] ni de la capa [entites].