Capítulo 1: Primeros pasos con Spring

Anuncio
Capítulo 1:
Primeros pasos con
Spring
Primer contacto con el framework
En este primer capítulo haremos una introducción
teórica y haremos unos ejemplos teóricos básicos para
empezar a tomar noción de lo que es Spring.
Javier Sevilla Sánchez
Trabajo de fin de carrera de la Ingeniería Técnica en
Informática de Gestión (I.T.I.G)
Contenido
Introducción al framework de Spring............................................................................................ 4
Inyección de dependencia e inversión de control ........................................................................ 4
Módulos .................................................................................................................................... 4
El contenedor ........................................................................................................................ 5
Integración y acceso de Datos............................................................................................... 6
Web ....................................................................................................................................... 6
AOP ........................................................................................................................................ 6
Test ........................................................................................................................................ 6
Primeros pasos con Spring ............................................................................................................ 7
Mi primer Hola mundo con Spring ............................................................................................ 7
Inyección de Dependencia ID (Dependency injection) ................................................................. 9
Inyección de dependencia en la práctica .................................................................................. 9
Programación orientada a aspectos............................................................................................ 12
¿Qué ventajas tenemos con AOP? .......................................................................................... 13
Resumen...................................................................................................................................... 13
Introducción al framework de Spring
Spring es un framework de código abierto de desarrollo de aplicaciones para la plataforma
Java. La primera versión fue escrita por Rod Jonhson. Es una plataforma Java que otorga una
infraestructura de apoyo global al desarrollo de aplicaciones Java. De este modo, Spring se
encarga de la infraestructura para que nosotros nos centremos en la aplicación.
Unos ejemplos pueden ser:




Inyección de dependencia e inversión de control.
Integración del acceso a datos.
Facilitar el desarrollo de aplicaciones web separando claramente las partes del
modelo, vista y controlador.
Poder ejecutar métodos transaccionales en una base de datos sin necesidad de lidiar
con API de transacción, métodos remotos sin tener que lidiar con API de
procedimientos remotos, métodos de gestión sin JMX, control de mensajes sin JMS...
Inyección de dependencia e inversión de control
El término “Aplicación Java” es un término tan amplio que podría ir desde un applet hasta
aplicaciones empresariales en servidores de nivel n.
Java proporciona una gran cantidad de herramientas para desarrollar aplicaciones, pero carece
de medios para organizar los elementos. Normalmente es el arquitecto Java el que se encarga
de esta tarea pudiendo utilizar patrones.
La inversión de control de Spring lo que hace es preocuparse de proporcionar una manera
formal de creación de componentes dispares de una manera homogénea y de una manera
funcional. Codifica componentes que se integran en las aplicaciones.
Diversas instituciones y empresas eligen Spring como una manera de diseñar aplicaciones
robustas fáciles de mantener.
Módulos
El framework de Spring consiste en elementos organizados en veinte módulos. Estos módulos
se agrupan en el Contenedor (core container), Acceso a datos e integración, modelo vista
controlador (módulo web MVC), aspectos (AOP), instrumentación y test.
El siguiente diagrama muestra cómo se divide:
El contenedor
El contenedor consiste en un núcleo, objetos bean, un contexto y un lenguaje de expresiones.
El núcleo y los beans son la parte fundamental de Spring, incluyendo la inversión de control y
la inyección de dependencia. Este contenedor es una versión más compleja del patrón Factory.
Elimina la necesidad de programar singletons y permite desacoplar la configuración y
especificación de dependencias de la lógica de programación.
El contexto se construye sobre la sólida base del núcleo. Así permite determinadas
configuraciones. Así la internacionalización, propagación de eventos, lectura de recursos o la
creación de contextos (como el web) formarán parte de este módulo.
Los Lenguajes de expresión permiten una potente herramienta de consulta y manipulación de
un objeto en tiempo de ejecución. Es una extensión del “Unified EL”, especificado en la
especificación JSP 2.1. El lenguaje permite asignar y obtener valores de las propiedades,
asignar propiedades, invocar métodos, acceder al contexto de matrices, listas, índices,
operadores aritméticos y lógicos, variables, y obtención de objetos por nombre del contendor
de Spring.
Integración y acceso de Datos
La capa de Integración y acceso a datos consiste en la integración de los módulos JDBC, ORM,
OXM, JMS y de transacción.
El módulo JDBC otorga una capa de abstracción que elimina la necesidad de crear código
tedioso y trasforma las excepciones generadas por el proveedor de base de datos.
El módulo ORM otorga una integración con los APIS más populares de ORM como puedan ser
JPA, JDO, Hibernate o iBatis.
El módulo OXM otorga una capa de abstracción para el mapeo Objeto/XML en distintas
implementaciones como JAXB, Castor, XMLBeans, JiBX o XStream.
El módulo JMS contiene características para la producción y consumo de mensajes.
El módulo de Transacción permite transacciones programáticas y declarativas para las clases
que implementan interfaces especiales y para todos los POJO.
Web
La capa web consiste en los módulos Web, Web-Servlet, Web-Struts y Web-Portlet.
El módulo Web permite integración básica de características como la subida multiparte de un
fichero, la inicialización de la inversión de control del contenedor usando listeners Servlet y un
contexto de lógica web.
El módulo Servlet contiene la implementación modelo vista controlador. El framework Spring
MVC permite una separación entre el modelo, el código y los formularios web y se integra con
todas las otras características de Spring.
El módulo Web-Struts permite la integración de clases integrando Struts, actualmente este
soporte esta obsoleto en Spring 3.0.
El módulo Web-Portlet permite las características web en sistemas empotrados.
AOP
El módulo AOP de Spring permite una implementación de programación orientada a aspectos
permitiendo definir métodos e interceptores, puntos de corte, etc. Para desacoplar el código.
Permite la integración con AspectJ
Él módulo de instrumentación otorga instrumentación de clases así como un cargador de claes
a ser usadas en determinadas aplicaciones de servidor.
Test
El módulo de test permite probar las aplicaciones de Spring y los componentes con JUnit o
TestNG. Permite la carga consistente de contextos de Spring. Así se permiten objetos mock
que prueban tu código de manera aislada.
Primeros pasos con Spring
La Inyección de Dependencia es un patrón de diseño orientado a objetos, en el que se inyectan
objetos a una clase en lugar de ser la propia clase quien cree objetos mediante constructores.
Como para muestra un botón, haremos un ejemplo “Hola Mundo” en el que se plasmarán los
conceptos básicos.
Empezaremos creando una clase interfaz “Saludo”, a pesar de que no es necesario para el
ejemplo ni para el uso de Spring, es una buena práctica ya que potencia el uso de la inyección
de dependencia, hace más fácil las pruebas y aumenta la abstracción entre otras ventajas.
Mi primer Hola mundo con Spring
Interfaz Saludo
package es.uah.tfc.javiersevilla.holamundo;
public interface Saludo {
String getSaludo();
void setSaludo(String saludo);
void saluda();
}
Vemos cómo esta interfaz hace que cualquier clase que la implemente cumpla con la
característica de los beans de tener métodos getters y setters. El siguiente paso es crear una
clase que implemente esa interfaz, la llamaremos SaludoImp. Crearemos un constructor vacío
al igual que un constructor con argumento para poder ilustrar las dos maneras que tiene
Spring de inyectar dependencias a un Bean.
Implementación SaludoImpl
package es.uah.tfc.javiersevilla.holamundo;
public class SaludoImpl implements Saludo {
private String saludo;
public SaludoImpl(String saludo){
this.saludo = saludo;
}
public SaludoImpl(){
}
public String getSaludo() {
return this.saludo;
}
public void setSaludo(String saludo) {
this.saludo = saludo;
}
public void saluda() {
System.out.println(saludo);
}
}
Hay que hacer hincapié en que en ningún momento se instancia un objeto para el atributo
saludo de la clase String sino que éste será inyectado.
Para comprender esto veamos el siguiente fichero de configuración xml.
Fichero de configuración XML
<?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="saludoMetodo"
class="es.uah.tfc.javiersevilla.holamundo.SaludoImpl">
<property name="saludo" value="¡¡Hola mundo!! (método)" />
</bean>
<bean id="saludoConstructor"
class="es.uah.tfc.javiersevilla.holamundo.SaludoImpl">
<constructor-arg value="¡¡Hola mundo!! (constructor)"/>
</bean>
</beans>
Este fichero será el que Spring utilice para la creación de Beans, vemos como se crean dos uno
haciendo uso de la inyección por parámetro y otro haciendo uso de la inyección por
constructor.
Ya están listos todos los componentes, sólo falta ver la puesta en marcha. Para ello crearemos
una clase con un método main.
package es.uah.tfc.javiersevilla.holamundo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HolaMundo {
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("holamundo.xml");
Saludo saludoConstructor = (Saludo)
ctx.getBean("saludoConstructor");
saludoConstructor.saluda();
Saludo saludoMetodo = (Saludo) ctx.getBean("saludoMetodo");
saludoMetodo.saluda();
}
}
Fijémonos en el código, vemos como ApplicationContext es el contenedor el cual hemos
cargado con el fichero XML. Este contenedor tiene los beans definidos en el fichero y podemos
acceder a ellos mediante su identificación.
Con este ejemplo queda esbozado el concepto de inyección de dependencia, pasemos a
explicar este término de un modo más amplio.
Inyección de Dependencia ID (Dependency injection)
El anterior ejemplo es algo muy sencillo, las aplicaciones no son como el HolaMundo sino que
suelen estar compuestas por diversas clases que operan de forma conjunta para un fin.
Tradicionalmente eran los propios objetos los responsables de obtener las referencias a otros
objetos con los que colaboraba haciendo un código muy acoplado y muy poco “testeable”. La
inyección de dependencia consiste en que estas dependencias las otorgue una entidad externa
inyectándolas en los objetos. Así la responsabilidad se delega en la entidad externa, haciendo
clases más simples.
Si un objeto sólo conoce sus dependencias mediante interfaces bien definidas, podremos
cambiar la implementación del objeto del que depende sin que se sepa la diferencia es decir
tendremos acoplamiento débil.
Inyección de dependencia en la práctica
Imaginemos que nos piden una aplicación de gestión para la universidad, en ella habría
alumnos, profesores, titulaciones, cursos, asignaturas, temarios, apuntes… etc. Pero de forma
sencilla y muy resumida diremos que un estudiante estudia una carrera y al finalizar obtiene
un título. Bajo esta premisa diríamos que el estudiante es el responsable de matricularse en la
carrera, estudiar y así obtener el título.
Para recrear este escenario usando la inyección de dependencia empezaríamos definiendo
claramente las interfaces que entren en juego como puedan ser Alumno, Carrera y Diploma.
Habrá relación entre ellas, pero debemos de crear un código en el cual las clases que
implementen estos interfaces conozcan lo mínimo posible de las clases de las cuales
dependen, es decir, los objetos sólo han de conocer el interfaz y su implementación ha de ser
inyectada en las clases dependientes.
Código del Interface Carrera:
package es.uah.uahdi.model;
public interface Carrer {
public void setName(String carrerName);
public void setUniversityName(String universityName);
public Certificate graduate();
}
Código del Interface Alumno:
package es.uah.uahdi.model;
public interface Student {
public
public
public
public
void setCarrer(Carrer carrer);
String getName();
void setName(String name);
Certificate study();
}
Código del Interface Diploma:
package es.uah.uahdi.model;
public interface Certificate {
public String getCarrerName();
public void setCarrerName(String carrerName);
public String getUniversityName();
public void setUniversityName(String universityName);
}
Código de la implementación de Carrera:
package es.uah.uahdi.model;
public class CarrerImp implements Carrer {
private String carrerName;
private String universityName;
public void setName(String carrerName) {
this.carrerName = carrerName;
}
public void setUniversityName(String universityName) {
this.universityName = universityName;
}
public Certificate graduate() {
return new UniversityCertificate(carrerName, universityName);
}
}
Código de la implementación de Alumno:
package es.uah.uahdi.model;
public class StudentImp implements Student {
private String name;
private Carrer carrer;
public StudentImp() {
}
public Carrer getCarrer() {
return carrer;
}
public void setCarrer(Carrer carrer) {
this.carrer = carrer;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Certificate study() {
return this.carrer.graduate();
}
}
Código de la implementación de Diploma:
package es.uah.uahdi.model;
public class UniversityCertificate implements Certificate{
private String carrerName;
private String universityName;
public UniversityCertificate(String carrerName, String universityName) {
this.carrerName = carrerName;
this.universityName = universityName;
}
public String getCarrerName() {
return this.carrerName;
}
public void setCarrerName(String carrerName) {
this.carrerName = carrerName;
}
public String getUniversityName() {
return universityName;
}
public void setUniversityName(String universityName) {
this.universityName = universityName;
}
}
Fichero de configuración de Spring:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="itig"
class="es.uah.uahdi.model.CarrerImp">
<property name="universityName" value="Universidad de Alcalá"/>
<property name="name" value="Ingeniería Técnica en Informática de
Gestión"/>
</bean>
<bean id="juanito"
class="es.uah.uahdi.model.StudentImp">
<property name="name" value="Juan Aurelio Gonzalez"/>
<property name="carrer" ref="itig"/>
</bean>
</beans>
En el fichero de configuración vemos como hemos declarado dos beans el primero con el
nombre “itig” el cual tiene dos propiedades y el otro “juanito” que tiene inyectado el bean
“itig”.
La clase principal cargará el contexto, obtendrá el bean juanito y obtendrá un diploma al
ejecutar el método de estudiar de juanito. Es importante destacar que gracias a que hemos
creado interfaces y a su vez implementaciones de estas hemos podido crear un código más
mantenible y reutilizable ya que cada implementación no conoce las implementaciones de las
demás, tan sólo conoce su interfaz. Esto hace un código menos acoplado y probable de
manera unitaria.
Programación orientada a aspectos
La programación orientada a aspectos hace que las funcionalidades de los componentes de las
aplicaciones sean más reutilizables. La programación orientada a aspectos (AOP) es una
técnica de programación que promueve que los sistemas estén bien divididos por
incumbencias. Así cada componente es responsable de una parte (gestión de transacciones,
gestión de registros, gestión de seguridad, gestión de de trazas… etc.) . Sin embargo,
típicamente los componentes acaban llevando funcionalidades que están fuera de su función y
que hacen que aumente la complejidad del código. Los principales problemas son que el
código que implementa las incumbencias del sistema se repite por cada componente que lo
necesite haciendo que si hay un cambio se tendrá que realizar en cada módulo que lo
implemente, en vez de en un sitio sólo y que los componentes tienen código que no es de su
funcionalidad principal.
¿Qué ventajas tenemos con AOP?
Como hemos explicado, sin AOP cada componente conoce las funcionalidades de los
demás, introduciendo complejidad adicional a su funcionalidad principal, como resultado, los
objetos empresariales están más implicados con los sistemas de servicios.
AOP hace posible poner en módulos estos servicios y después aplicarlos de manera declarativa
a los componentes que deberían afectar aumentando así la cohesión y haciendo que los POJO
se mantengan simples. Así los aspectos “envuelven” a los demás componentes haciéndolos
más sencillos evitando ensuciarles con lógica de transacciones, seguridad o trazas.
Siguiendo con la línea de la aplicación de la universidad, hagamos un ejemplo que clarifique
este concepto.
Resumen
En este capítulo hemos presentado Spring, viendo que es un framework que facilita la creación
de aplicaciones haciéndolas más comprensibles, desacopladas y fáciles de mantener. Hemos
presentado sus principales componentes haciendo una breve visión de lo que Spring puede
hacer por nosotros.
Hemos hecho una primera visión de los módulos en los que se divide Spring, Estos módulos se
agrupan en el Contenedor (core container), Acceso a datos e integración, modelo vista
controlador (módulo web MVC), aspectos (AOP), instrumentación y test.
Más tarde, a modo de prueba, hemos creado nuestra primera aplicación con Spring, viendo de
una manera más práctica su funcionamiento. Hemos hecho una breve introducción a la
inyección de dependencia así como a la programación orientada a aspectos.
Descargar