29.10.2014 Views

Apartado 3.4: Implementación de los Casos de Uso con Spring

Apartado 3.4: Implementación de los Casos de Uso con Spring

Apartado 3.4: Implementación de los Casos de Uso con Spring

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>3.4</strong> Implementación <strong>de</strong> <strong>los</strong><br />

<strong>Casos</strong> <strong>de</strong> <strong>Uso</strong> <strong>con</strong> <strong>Spring</strong>


Índice<br />

• Introducción a <strong>Spring</strong><br />

• Declaración y Configuración <strong>de</strong> “beans”<br />

• Excepciones <strong>de</strong> Persistencia<br />

• Declaración <strong>de</strong> DataSources<br />

• Integración <strong>con</strong> Hibernate 3<br />

• Gestión <strong>de</strong> Transacciones


¿Qué es <strong>Spring</strong>? (1)<br />

• Framework <strong>de</strong> código abierto creado por Rod<br />

Johnson<br />

• http://www.springframework.org<br />

• Motivación: Facilitar el <strong>de</strong>sarrollo <strong>de</strong> aplicaciones<br />

Java EE, promoviendo buenas prácticas <strong>de</strong> diseño y<br />

programación<br />

• Simplifica el uso <strong>de</strong> muchas <strong>de</strong> las APIs <strong>de</strong> Java EE<br />

• Dispone <strong>de</strong> alternativas a algunas <strong>de</strong> las APIs <strong>de</strong> Java EE<br />

• Internamente se apoyan en APIs <strong>de</strong> Java EE <strong>de</strong> más bajo nivel<br />

• Facilita el uso <strong>de</strong> patrones <strong>de</strong> diseño ampliamente<br />

re<strong>con</strong>ocidos <strong>de</strong>ntro <strong>de</strong> la industria <strong>de</strong>l <strong>de</strong>sarrollo <strong>de</strong> software<br />

(Factory, Abstract Factory, Buil<strong>de</strong>r, Decorator, Service<br />

Locator, etc.)<br />

• Soporte para capa mo<strong>de</strong>lo e interfaz Web<br />

• Es modular: es posible usar algunos <strong>de</strong> <strong>los</strong> módu<strong>los</strong> sin<br />

comprometerse <strong>con</strong> el uso <strong>de</strong>l resto


¿Qué es <strong>Spring</strong>? (y 2)<br />

• Nosotros utilizaremos el soporte <strong>de</strong> <strong>Spring</strong> para<br />

implementar casos <strong>de</strong> uso a nivel <strong>de</strong> capa mo<strong>de</strong>lo<br />

• Alternativa al uso <strong>de</strong> <strong>los</strong> Session Bean <strong>de</strong> EJB<br />

• Pue<strong>de</strong> actuar como una capa <strong>de</strong> integración entre<br />

diferentes APIs (JDBC, JNDI, etc.) y frameworks<br />

• En nuestro caso entre Tapestry e Hibernate


Conceptos Básicos en <strong>Spring</strong><br />

• Inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias (Depen<strong>de</strong>ncy Injection,<br />

DI)<br />

• Programación orientada a aspectos (Aspect-Oriented<br />

Programming, AOP)


Inyección <strong>de</strong> Depen<strong>de</strong>ncias<br />

• Tradicionalmente cada objeto es responsable <strong>de</strong><br />

obtener sus propias referencias a <strong>los</strong> objetos <strong>con</strong> <strong>los</strong><br />

que colabora<br />

• Cuando se aplica la Inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias (DI),<br />

alguna entidad externa es la responsable <strong>de</strong><br />

proporcionar a un objeto sus <strong>de</strong>pen<strong>de</strong>ncias cuando<br />

se crea el objeto (las <strong>de</strong>pen<strong>de</strong>ncias se inyectan en el<br />

objeto)<br />

• Ventajas<br />

• Pérdida <strong>de</strong> acoplamiento entre <strong>los</strong> objetos<br />

• Si un objeto <strong>con</strong>oce sus <strong>de</strong>pen<strong>de</strong>ncias a través <strong>de</strong> interfaces,<br />

es posible cambiar la implementación <strong>de</strong> esas <strong>de</strong>pen<strong>de</strong>ncias<br />

transparentemente para el objeto que las <strong>con</strong>tiene


Programación Orientada a Aspectos (AOP)<br />

• Técnica <strong>de</strong> programación que promueve la separación <strong>de</strong><br />

funcionalida<strong>de</strong>s<br />

• AOP: http://en.wikipedia.org/wiki/Aspect-oriented_programming<br />

• Algunos servicios son utilizados repetidas veces en diferentes<br />

componentes <strong>de</strong> un sistema, cuya responsabilidad principal es<br />

otra<br />

• E.g. servicios <strong>de</strong> logging o gestión <strong>de</strong> transacciones y seguridad<br />

• Se <strong>con</strong>ocen como aspectos transversales ("cross cutting <strong>con</strong>cerns”)<br />

• Un framework <strong>de</strong> AOP hace posible modularizar estos aspectos<br />

o servicios y aplicar<strong>los</strong> <strong>de</strong>clarativamente a <strong>los</strong> componentes<br />

que <strong>los</strong> precisen<br />

• Cada aspecto se implementa en un único punto<br />

• Declarativamente se especifican <strong>los</strong> métodos que el framework<br />

tiene que interceptar para aplicarles el o <strong>los</strong> aspectos que el<br />

<strong>de</strong>sarrollador <strong>de</strong>sea<br />

• Cada componente <strong>de</strong>be preocuparse únicamente <strong>de</strong> su<br />

funcionalidad principal sin preocuparse <strong>de</strong> <strong>los</strong> servicios <strong>de</strong>l sistema<br />

que precise


Módu<strong>los</strong>/Paquetes (1)<br />

DAO<br />

<strong>Spring</strong> JDBC<br />

Transaction<br />

management<br />

ORM<br />

Hibernate<br />

JPA<br />

JDO<br />

TopLink<br />

OJB<br />

iBatis<br />

AOP<br />

<strong>Spring</strong> AOP<br />

Integración AspectJ<br />

JEE<br />

JMX<br />

JMS<br />

JCA<br />

Remotig<br />

EJBs<br />

Email<br />

Web<br />

<strong>Spring</strong> Web MVC<br />

Framework Integration<br />

Struts<br />

WebWork<br />

Tapestry<br />

JSF<br />

Rich View Support<br />

JSPs<br />

Velocity<br />

FreeMarker<br />

PDF<br />

Jasper Reports<br />

Excel<br />

<strong>Spring</strong> Portlet MVC<br />

Core<br />

IoC Container


Módu<strong>los</strong>/Paquetes (2)<br />

• Core<br />

• Constituye la parte fundamental <strong>de</strong>l framework y<br />

proporciona la característica <strong>de</strong> Inyección <strong>de</strong> Depen<strong>de</strong>ncias<br />

(DI) / Inversión <strong>de</strong> Control (IoC)<br />

• Proporciona una implementación sofisticada <strong>de</strong>l patrón<br />

Factoría que permite <strong>de</strong>sacoplar la <strong>con</strong>figuración y<br />

especificación <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias <strong>de</strong> la lógica <strong>de</strong> la aplicación<br />

• DAO<br />

• Proporciona una capa <strong>de</strong> abstracción sobre JDBC que<br />

elimina la necesidad <strong>de</strong> codificar y analizar <strong>los</strong> códigos <strong>de</strong><br />

error específicos <strong>de</strong> cada BBDD<br />

• También proporciona una manera <strong>de</strong> gestionar<br />

transacciones tanto programática como <strong>de</strong>clarativamente,<br />

no sólo para clases que implementen ciertas interfaces, sino<br />

para cualquier objeto Java (POJO)


Módu<strong>los</strong>/Paquetes (y 3)<br />

• ORM<br />

• Proporciona capas <strong>de</strong> integración para las APIs <strong>de</strong><br />

mapeadores objeto-relacionales más populares: Hibernate,<br />

JPA, JDO, iBatis<br />

• Utilizando este paquete es posible utilizar cualquiera <strong>de</strong><br />

estos mapeadores objeto-relacionales en combinación <strong>con</strong><br />

las <strong>de</strong>más características que ofrece <strong>Spring</strong> (como por<br />

ejemplo <strong>con</strong> la gestión <strong>de</strong>clarativa <strong>de</strong> transacciones)<br />

• AOP<br />

• Proporciona una implementación <strong>de</strong>l paradigma <strong>de</strong> la<br />

programación orientada a aspectos (<strong>con</strong>forme a la AOP<br />

Alliance), que es utilizada, transparentemente para el<br />

programador, por parte otros paquetes <strong>de</strong> <strong>Spring</strong>, pero que<br />

también pue<strong>de</strong> ser usada directamente


El Contenedor (1)<br />

• El <strong>con</strong>tenedor <strong>de</strong> IoC es el núcleo <strong>de</strong>l sistema<br />

• Responsable <strong>de</strong> la creación y <strong>con</strong>figuración <strong>de</strong> <strong>los</strong> Beans<br />

• Nota: Un bean, en el <strong>con</strong>texto <strong>de</strong> <strong>Spring</strong>, es un POJO que es<br />

creado y manejado por el <strong>con</strong>tenedor <strong>de</strong> IoC<br />

• La interfaz BeanFactory o su hija<br />

ApplicationContext representan la interfaz <strong>de</strong>l<br />

<strong>con</strong>tenedor<br />

• <strong>Spring</strong> proporciona varias implementaciones


El Contenedor (2)<br />

• Instanciación<br />

try {<br />

ApplicationContext ctx =<br />

new ClassPathXmlApplicationContext(<br />

GlobalNames.SPRING_CONFIG_FILE_LOCATION);<br />

AccountService accountService =<br />

(AccountService) ctx.getBean("accountService");<br />

...<br />

} catch (Exception e) {<br />

}<br />

e.printStackTrace();


El Contenedor (y 3)<br />

• ClassPathXmlApplicationContext<br />

• Permite <strong>de</strong>clarar <strong>los</strong> objetos que componen la aplicación, y<br />

las <strong>de</strong>pen<strong>de</strong>ncias entre el<strong>los</strong> en XML<br />

• A partir <strong>de</strong> <strong>los</strong> metadatos <strong>de</strong> <strong>con</strong>figuración en XML es capaz<br />

<strong>de</strong> crear y <strong>con</strong>figurar <strong>los</strong> objetos que componen la aplicación<br />

• A través <strong>de</strong>l método getBean es posible obtener una<br />

referencia a <strong>los</strong> objetos <strong>de</strong>clarados, a partir <strong>de</strong> su nombre


• Es equivalente a<br />

Declaración <strong>de</strong> Beans (1)<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


Declaración <strong>de</strong> Beans (2)<br />

• Se <strong>de</strong>claran <strong>con</strong> la etiqueta bean<br />

• Parámetros básicos<br />

• id: Nombre o i<strong>de</strong>ntificador <strong>de</strong>l bean<br />

• class: Clase <strong>de</strong> implementación <strong>de</strong>l bean<br />

• Inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias basada en “setters”<br />

• Permite inyectar valores u otros beans (a través <strong>de</strong><br />

referencias), invocando al método set correspondiente <strong>de</strong>l<br />

bean sobre el que se está realizando la inyección<br />

• Se indica el nombre <strong>de</strong> la propiedad que se <strong>de</strong>sea inyectar y el<br />

valor que se le <strong>de</strong>sea proporcionar


Declaración <strong>de</strong> Beans (y 3)<br />

• Inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias basada en “setters”<br />

(<strong>con</strong>t)<br />

• Es posible especificarlas<br />

• A través <strong>de</strong> un elemento anidado property, que acepta <strong>los</strong><br />

siguientes atributos<br />

• name: Nombre <strong>de</strong> la propiedad don<strong>de</strong> se <strong>de</strong>sea inyectar el valor<br />

• value: Para inyectar un valor <strong>con</strong>stante<br />

• ref: Para inyectar otro bean a partir <strong>de</strong> su nombre<br />

• Con sintaxis abreviada (utilizando el espacio <strong>de</strong> nombres p) a<br />

través <strong>de</strong> <strong>los</strong> atributos<br />

• p:nombrePropiedad: Para inyectar un valor <strong>con</strong>stante en la<br />

propiedad indicada<br />

• p:nombrePropiedad-ref: Para inyectar otro bean a partir <strong>de</strong><br />

su nombre en la propiedad indicada<br />

• El bean se crea a partir <strong>de</strong> su <strong>con</strong>structor vacío y a<br />

<strong>con</strong>tinuación se invocan <strong>los</strong> métodos set <strong>con</strong> <strong>los</strong> valores<br />

a<strong>de</strong>cuados


Beans <strong>de</strong> la capa mo<strong>de</strong>lo <strong>de</strong> MiniBank (spring-<strong>con</strong>fig.xml)<br />

<br />


Beans <strong>de</strong> la capa mo<strong>de</strong>lo <strong>de</strong> MiniBank<br />

• Declaramos <strong>los</strong> siguientes beans<br />

• Un bean para cada DAO Hibernate<br />

• Un bean para la implementación <strong>de</strong> la fachada<br />

• Un bean para la SesionFactory (que usan <strong>los</strong> DAOs <strong>de</strong><br />

Hibernate)<br />

• Depen<strong>de</strong>ncias entre beans<br />

• La fachada usa <strong>los</strong> DAOs<br />

• Los DAOs usan la SesionFactory<br />

• Utilizamos la DI <strong>de</strong> <strong>Spring</strong> basada en métodos set<br />

para resolver las <strong>de</strong>pen<strong>de</strong>ncias entre beans


AccountServiceImpl.java<br />

public class AccountServiceImpl implements AccountService {<br />

private AccountDao accountDao;<br />

private AccountOperationDao accountOperationDao;<br />

public void setAccountDao(AccountDao accountDao) {<br />

this.accountDao = accountDao;<br />

}<br />

public void setAccountOperationDao(<br />

AccountOperationDao accountOperationDao) {<br />

this.accountOperationDao = accountOperationDao;<br />

}<br />

}<br />

...


AccountDaoHibernate.java y<br />

AccountDaoOperationHibernate.java<br />

public class AccountDaoHibernate extends<br />

GenericDaoHibernate<br />

implements AccountDao {<br />

}<br />

...<br />

public class AccountOperationDaoHibernate<br />

extends GenericDaoHibernate<br />

implements AccountOperationDao {<br />

}<br />

...


GenericAccountDAO.java<br />

public class GenericDaoHibernate<br />

implements GenericDao {<br />

}<br />

private SessionFactory sessionFactory;<br />

...<br />

public void setSessionFactory(SessionFactory sessionFactory) {<br />

this.sessionFactory = sessionFactory;<br />

}<br />

...


Beans: Inyección <strong>de</strong> Depen<strong>de</strong>ncias<br />

accountDao<br />

AccountDaoHibernate<br />

- sessionFactory : SessionFactory<br />

accountService<br />

+ métodos set<br />

AccountServiceImpl<br />

- accountDao : AccountDao<br />

- accountOperationDao :<br />

AccountOperationDao<br />

sessionFactory<br />

+ métodos set<br />

accountOperationDao<br />

AccountOperationDaoHibernate<br />

- sessionFactory : SessionFactory<br />

+ métodos set


Ámbito <strong>de</strong> <strong>los</strong> Beans<br />

• El ámbito <strong>de</strong> un bean se especifica a través <strong>de</strong>l<br />

atributo scope <strong>de</strong> la etiqueta bean<br />

• singleton (valor por <strong>de</strong>fecto)<br />

• El <strong>con</strong>tenedor usa siempre la misma instancia (ya sea cuando<br />

se le pi<strong>de</strong> a través <strong>de</strong> la API o cuando necesita inyectarlo)<br />

• prototype<br />

• Indica que el <strong>con</strong>tenedor <strong>de</strong>be crear una nueva instancia <strong>de</strong>l<br />

bean cada vez que se precise una<br />

• Pue<strong>de</strong> ser necesario, por ejemplo, si el bean tiene estado<br />

• OJO <strong>con</strong> <strong>los</strong> beans <strong>de</strong> tipo singleton <strong>con</strong><br />

<strong>de</strong>pen<strong>de</strong>ncias <strong>con</strong> beans <strong>de</strong> tipo prototype


Más sobre Declaración <strong>de</strong> Beans<br />

• Otras funcionalida<strong>de</strong>s que ofrece <strong>Spring</strong><br />

• Instanciación <strong>de</strong> beans a partir <strong>de</strong> factorías<br />

• Inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias a través <strong>de</strong> <strong>con</strong>structores<br />

• Los valores o referencias a otros beans se inyectan a través <strong>de</strong><br />

<strong>los</strong> argumentos <strong>de</strong> un <strong>con</strong>structor<br />

• Inyección <strong>de</strong> propieda<strong>de</strong>s multivaluadas (listas, <strong>con</strong>juntos,<br />

mapas)<br />

• Autoinyección (autowiring)<br />

• Por nombre: Busca un bean <strong>con</strong> el mismo id que la propiedad<br />

• Por tipo: Busca un bean <strong>con</strong> el mismo tipo que la propiedad<br />

• Por <strong>con</strong>structor: Busca uno o más beans cuyos tipos coincidan<br />

<strong>con</strong> <strong>los</strong> parámetros <strong>de</strong> uno <strong>de</strong> <strong>los</strong> <strong>con</strong>structores <strong>de</strong> ese bean<br />

• Inicialización y liberación <strong>de</strong> recursos <strong>de</strong> un bean a través <strong>de</strong><br />

métodos que <strong>de</strong>ben ser invocados justo <strong>de</strong>spués <strong>de</strong> haberse<br />

creado y justo antes <strong>de</strong> ser <strong>de</strong>struido respectivamente<br />

• Etc.


Excepciones <strong>de</strong> Persistencia (1)<br />

• En JDBC se lanza la excepción<br />

java.sql.SQLException cuando se produce<br />

cualquier tipo <strong>de</strong> error en el acceso a <strong>los</strong> datos<br />

• Problema: Hay que capturarla siempre y analizarla para<br />

saber <strong>de</strong> qué tipo <strong>de</strong> error se trata<br />

• Algunos frameworks (e.g. Hibernate) ofrecen una<br />

jerarquía <strong>de</strong> excepciones más <strong>de</strong>scriptiva (una<br />

excepción diferente para cada tipo <strong>de</strong> error)<br />

• Ventaja: Permite diferenciar entre qué tipos <strong>de</strong> errores<br />

capturar<br />

• Problema: Son específicas <strong>de</strong>l framework utilizado para<br />

realizar la persistencia <strong>de</strong> <strong>los</strong> datos


Excepciones <strong>de</strong> Persistencia (y 2)<br />

• <strong>Spring</strong> proporciona una jerarquía <strong>de</strong> excepciones <strong>de</strong><br />

acceso a datos (heredan <strong>de</strong><br />

DataAccessException) que resuelve ambos<br />

problemas:<br />

• Cada excepción representa un error <strong>con</strong>creto<br />

• No son específicas <strong>de</strong>l framework <strong>de</strong> persistencia <strong>de</strong> datos<br />

utilizado, por tanto se oculta a las capas superiores<br />

• Son excepciones unchecked<br />

• Para que <strong>Spring</strong> realice la <strong>con</strong>versión entre las<br />

excepciones nativas y la jerarquía propia es necesario<br />

<strong>de</strong>clarar el siguiente bean:<br />


DataSources<br />

• In<strong>de</strong>pendientemente <strong>de</strong>l framework <strong>de</strong> persistencia<br />

utilizado probablemente se necesitará <strong>con</strong>figurar una<br />

referencia a un DataSource<br />

• <strong>Spring</strong> proporciona, entre otras, las siguientes<br />

opciones para <strong>con</strong>figurar un bean <strong>de</strong> tipo<br />

DataSource<br />

• DataSources <strong>de</strong>finidos directamente sobre un driver JDBC<br />

• DataSources que son localizados vía JNDI<br />

• Cualquier <strong>con</strong>tenedor Java EE pue<strong>de</strong> poner accesible vía JNDI<br />

un DataSource (que normalmente implementará pool <strong>de</strong><br />

<strong>con</strong>exiones)


DataSources JDBC<br />

<br />

• DriverManagerDataSource: Devuelve una nueva<br />

<strong>con</strong>exión a la BD cada vez que se le pi<strong>de</strong> una<br />

• Es <strong>de</strong>cir, no implementa la estrategia pool <strong>de</strong> <strong>con</strong>exiones<br />

(<strong>con</strong>ceptualmente similar al SimpleDataSource estudiado<br />

en el apartado 3.1)<br />

• Debe indicársele como propieda<strong>de</strong>s<br />

• El nombre <strong>de</strong> la clase <strong>de</strong>l driver JDBC<br />

• La URL <strong>de</strong> <strong>con</strong>exión a la BD<br />

• El usuario para <strong>con</strong>ectarse a la BD<br />

• La <strong>con</strong>traseña <strong>de</strong>l usuario indicado<br />

• Útil para tests <strong>de</strong> integración


DataSources JNDI (1)<br />

• JNDI (Java Naming and Directory Interface)<br />

• Familia <strong>de</strong> paquetes javax.naming (Java SE)<br />

• Es una API que abstrae el acceso a un servicio <strong>de</strong> nombres y<br />

directorios (e.g. LDAP)<br />

• Es posible registrar objetos mediante un nombre jerárquico<br />

• Los servidores <strong>de</strong> aplicaciones Java EE exponen diversos objetos<br />

mediante JDNI<br />

• Los servidores <strong>de</strong> aplicaciones Java EE proporcionan<br />

implementaciones <strong>de</strong> DataSource<br />

• Cada objeto DataSource es accesible a partir <strong>de</strong> un nombre JNDI<br />

<strong>de</strong> la forma java:comp/env/XXX/ZZZ, don<strong>de</strong> XXX suele<br />

(recomendado) ser "jdbc" e YYY el nombre <strong>de</strong> un DataSource<br />

<strong>con</strong>creto<br />

• Habitualmente estos objetos DataSource implementan la estrategia<br />

<strong>de</strong> pool <strong>de</strong> <strong>con</strong>exiones<br />

• Requiere <strong>con</strong>figuración en el servidor (driver, URL, usuario,<br />

<strong>con</strong>traseña, parámetros específicos al pool, etc.)<br />

• Ej.: En Tomcat se <strong>de</strong>finen en <strong>con</strong>f/server.xml


DataSources JNDI (y 2)<br />

<br />

• El atributo jndiName se utiliza para indicar el nombre <strong>de</strong>l<br />

recurso accesible vía JNDI<br />

• Si la aplicación está ejecutándose <strong>de</strong>ntro <strong>de</strong> un servidor <strong>de</strong><br />

aplicaciones Java EE<br />

• El valor <strong>de</strong>l atributo resourceRef <strong>de</strong>be ser true<br />

• El nombre indicado en jndiName es relativo al <strong>con</strong>texto<br />

java:comp/env/<br />

• JndiObjectFactoryBean implementa<br />

org.springframework.beans.factory.FactoryBean<br />

• Los beans que implementan esta interfaz se <strong>de</strong>finen igual que el<br />

resto <strong>de</strong> beans, pero cuando se referencian <strong>de</strong>s<strong>de</strong> otros beans no<br />

se inyecta una instancia <strong>de</strong> ese tipo sino el objeto que <strong>de</strong>vuelve su<br />

método getObject<br />

• El método getObject <strong>de</strong> JndiObjectFactoryBean <strong>de</strong>vuelve el<br />

objeto asociado al nombre JNDI especificado en la <strong>con</strong>figuración


Integración <strong>con</strong> Hibernate 3 (1)<br />

• Los DAOs implementados <strong>con</strong> Hibernate necesitan un objeto <strong>de</strong><br />

tipo org.hibernate.SesionFactory <strong>de</strong>l que obtener la<br />

sesión actual<br />

• Como veremos más a<strong>de</strong>lante el gestor <strong>de</strong> transacciones <strong>de</strong><br />

Hibernate también precisa un objeto <strong>de</strong> ese tipo<br />

• La siguiente <strong>de</strong>claración permite <strong>de</strong>finir un bean para obtener<br />

un SessionFactory que utiliza las anotaciones <strong>de</strong> Hibernate<br />

en las entida<strong>de</strong>s<br />


Integración <strong>con</strong> Hibernate 3 (y 2)<br />

• Como ya hemos visto <strong>con</strong> anterioridad el bean<br />

sesionFactory se inyecta en <strong>los</strong> DAOs<br />

<br />


Transacciones<br />

• <strong>Spring</strong> no gestiona directamente las transacciones, sino que lo<br />

hace a través <strong>de</strong> una abstracción (patrón Strategy)<br />

• Interfaz<br />

org.springframework.transaction.PlatformTransactionManager<br />

• Se pue<strong>de</strong> trabajar <strong>con</strong> las transacciones in<strong>de</strong>pendientemente <strong>de</strong> la<br />

implementación <strong>de</strong>l gestor <strong>de</strong> transacciones <strong>con</strong>creto que se esté<br />

utilizando<br />

• <strong>Spring</strong> proporciona una serie <strong>de</strong> gestores <strong>de</strong> transacciones que<br />

<strong>de</strong>legan la responsabilidad <strong>de</strong> la gestión <strong>de</strong> las transacciones a<br />

implementaciones específicas <strong>de</strong> la plataforma utilizada<br />

• Se pue<strong>de</strong> trabajar <strong>con</strong> transacciones a través <strong>de</strong> la API Java <strong>de</strong><br />

<strong>Spring</strong>, pero también se pue<strong>de</strong>n <strong>de</strong>finir <strong>de</strong> forma <strong>de</strong>clarativa<br />

haciendo uso <strong>de</strong>l framework AOP <strong>de</strong> <strong>Spring</strong>, que incluye una<br />

implementación <strong>de</strong>l aspecto <strong>de</strong> transaccionalidad<br />

• Es posible hacerlo mediante XML o mediante anotaciones Java<br />

• Utilizaremos la opción <strong>de</strong> las anotaciones porque que simplifica la<br />

<strong>de</strong>claración <strong>de</strong> las transacciones


Transacciones <strong>con</strong> Hibernate 3<br />

• Si la capa <strong>de</strong> persistencia <strong>de</strong>l mo<strong>de</strong>lo está implementada <strong>con</strong><br />

Hibernate, entonces el gestor <strong>de</strong> transacciones a utilizar es el<br />

siguiente<br />


API Transacciones (1)<br />

public interface PlatformTransactionManager {<br />

TransactionStatus getTransaction(TransactionDefinition <strong>de</strong>finition)<br />

throws TransactionException;<br />

void commit(TransactionStatus status)<br />

throws TransactionException;<br />

}<br />

void rollback(TransactionStatus status)<br />

throws TransactionException;<br />

public interface TransactionStatus {<br />

boolean isNewTransaction();<br />

void setRollbackOnly();<br />

}<br />

boolean isRollbackOnly();


API Transacciones (y 2)<br />

• Un gestor <strong>de</strong> transacciones implementa la interfaz<br />

PlatformTransactionManager<br />

• TransactionException es una excepción unchecked<br />

• El método getTransaction <strong>de</strong>vuelve un objeto <strong>de</strong> tipo<br />

TransactionStatus en función <strong>de</strong> un parámetro <strong>de</strong> tipo<br />

TransactionDefinition<br />

• TransactionStatus representa una transacción<br />

• Pue<strong>de</strong> ser la transacción actual o una nueva<br />

• TransactionDefinition es una interfaz a través <strong>de</strong> la cual<br />

se pue<strong>de</strong>n especificar las características <strong>de</strong> la transacción que<br />

se quiere obtener (propagación, nivel <strong>de</strong> aislamiento, timeout,<br />

propiedad read-only)<br />

• La subinterfaz TransactionAttribute permite, a<strong>de</strong>más,<br />

especificar la lista <strong>de</strong> excepciones que provocan o no un rollback<br />

• Para utilizar <strong>los</strong> valores por <strong>de</strong>fecto pue<strong>de</strong> ser “null”<br />

• Los métodos commit y rollback se utilizan para hacer un<br />

commit o un rollback <strong>de</strong> la transacción que se les pasa


AOP: Gestión <strong>de</strong> Transacciones (1)<br />

public class AccountServiceImpl implements AccountService {<br />

static {<br />

ApplicationContext <strong>con</strong>text = ...;<br />

transactionManager = (PlatformTransactionManager) <strong>con</strong>text<br />

.getBean("transactionManager");<br />

}<br />

private static PlatformTransactionManager transactionManager;<br />

private AccountDao accountDao;<br />

private AccountOperationDao accountOperationDao;<br />

public void setAccountDao(AccountDao accountDao) {<br />

this.accountDao = accountDao;<br />

}<br />

public void setAccountOperationDao(<br />

AccountOperationDao accountOperationDao) {<br />

this.accountOperationDao = accountOperationDao;<br />

}


AOP: Gestión <strong>de</strong> Transacciones (2)<br />

public Account createAccount(Account account) {<br />

TransactionStatus transactionStatus =<br />

transactionManager.getTransaction(null);<br />

Iniciar<br />

transacción<br />

try {<br />

accountDao.create(account);<br />

} catch (RuntimeException e) {<br />

transactionManager.rollback(transactionStatus);<br />

}<br />

throw e;<br />

transactionManager.commit(transactionStatus);<br />

Finalizar<br />

transacción<br />

return account;<br />

}


AOP: Gestión <strong>de</strong> Transacciones (3)<br />

public void removeAccount(Long accountId)<br />

throws InstanceNotFoundException {<br />

TransactionStatus transactionStatus =<br />

transactionManager.getTransaction(null);<br />

Iniciar<br />

transacción<br />

try {<br />

accountDao.remove(accountId);<br />

} catch (RuntimeException e) {<br />

transactionManager.rollback(transactionStatus);<br />

throw e;<br />

} catch (InstanceNotFoundException e) {<br />

transactionManager.commit(transactionStatus);<br />

throw e;<br />

}<br />

transactionManager.commit(transactionStatus);<br />

Finalizar<br />

transacción<br />

}


AOP: Gestión <strong>de</strong> Transacciones (4)<br />

public void withdrawFromAccount(Long accountId, double amount)<br />

throws InstanceNotFoundException, InsufficientBalanceException {<br />

TransactionStatus transactionStatus =<br />

transactionManager.getTransaction(null);<br />

Iniciar<br />

transacción<br />

try {<br />

/* Find account. */<br />

Account account = accountDao.find(accountId);<br />

/* Modify balance. */<br />

double currentBalance = account.getBalance();<br />

if (currentBalance < amount) {<br />

throw new InsufficientBalanceException(accountId,<br />

currentBalance,amount);<br />

}<br />

account.setBalance(currentBalance - amount);<br />

accountDao.update(account);


AOP: Gestión <strong>de</strong> Transacciones (5)<br />

/* Register account operation. */<br />

accountOperationDao.create(new AccountOperation(account,<br />

Calendar.getInstance(), AccountOperation.Type.WITHDRAW,<br />

amount));<br />

} catch (RuntimeException e) {<br />

transactionManager.rollback(transactionStatus);<br />

throw e;<br />

} catch (InstanceNotFoundException e) {<br />

transactionManager.commit(transactionStatus);<br />

throw e;<br />

} catch (InsufficientBalanceException e) {<br />

transactionManager.commit(transactionStatus);<br />

throw e;<br />

}<br />

transactionManager.commit(transactionStatus);<br />

Finalizar<br />

transacción<br />

}<br />

...<br />

}


AOP: Gestión <strong>de</strong> Transacciones (6)<br />

• El código para todos <strong>los</strong> casos <strong>de</strong> uso transaccionales<br />

es similar:<br />

• Iniciar la transacción (<strong>con</strong> las propieda<strong>de</strong>s a<strong>de</strong>cuadas) a<br />

partir <strong>de</strong>l gestor <strong>de</strong> transacciones utilizado<br />

• El gestor <strong>de</strong> transacciones pue<strong>de</strong> <strong>de</strong>clararse en el archivo <strong>de</strong><br />

<strong>con</strong>figuración <strong>de</strong> <strong>Spring</strong> como un bean y obtenerlo a través <strong>de</strong>l<br />

método getBean <strong>de</strong>spués <strong>de</strong> instanciar el <strong>con</strong>tenedor<br />

• Ejecutar la lógica propia <strong>de</strong>l caso <strong>de</strong> uso<br />

• Finalizar transacción (commit o rollback) en función <strong>de</strong> si se<br />

ha producido alguna excepción o no y <strong>de</strong> su tipo<br />

• El código común para la gestión <strong>de</strong> las transacciones<br />

pue<strong>de</strong> eliminarse <strong>de</strong> la implementación <strong>de</strong> todos <strong>los</strong><br />

casos <strong>de</strong> uso que lo precisen, y <strong>de</strong>clarativamente<br />

<strong>de</strong>cir cuándo <strong>de</strong>be ejecutarse


AOP: Gestión <strong>de</strong> Transacciones (y 7)<br />

• Declarativamente es posible indicar<br />

• El gestor <strong>de</strong> transacciones a utilizar<br />

• Que <strong>los</strong> métodos createAccount, removeAccount y<br />

todos <strong>los</strong> <strong>de</strong>más <strong>de</strong> la clase AccountServiceImpl son<br />

transaccionales<br />

• <strong>Spring</strong> intercepta las invocaciones a <strong>los</strong> métodos <strong>de</strong>clarados<br />

como transaccionales:<br />

• [Antes <strong>de</strong> que se ejecute el método] Ejecuta el código<br />

necesario para comenzar la transacción<br />

• Declarativamente pue<strong>de</strong>n indicarse parámetros como, por<br />

ejemplo, el nivel <strong>de</strong> aislamiento <strong>de</strong>seado para la transacción<br />

• [Después <strong>de</strong> que se ejecute el método] Ejecuta el código<br />

necesario para finalizar la transacción (ya sea <strong>con</strong> un commit o<br />

un rollback)<br />

• Pue<strong>de</strong>n indicarse qué excepciones <strong>de</strong>ben provocar un rollback y<br />

cuales no


AccountServiceImpl.java (1)<br />

@Transactional<br />

public class AccountServiceImpl implements AccountService {<br />

private AccountDao accountDao;<br />

private AccountOperationDao accountOperationDao;<br />

public void setAccountDao(AccountDao accountDao) {<br />

this.accountDao = accountDao;<br />

}<br />

public void setAccountOperationDao(<br />

AccountOperationDao accountOperationDao) {<br />

this.accountOperationDao = accountOperationDao;<br />

}<br />

public Account createAccount(Account account) { ... }<br />

@Transactional(readOnly = true)<br />

public Account findAccount(Long accountId)<br />

throws InstanceNotFoundException { ... }<br />

public void addToAccount(Long accountId, double amount)<br />

throws InstanceNotFoundException { ... }


AccountServiceImpl.java (2)<br />

public void withdrawFromAccount(Long accountId, double amount)<br />

throws InstanceNotFoundException, InsufficientBalanceException {<br />

/* Find account. */<br />

Account account = accountDao.find(accountId);<br />

/* Modify balance. */<br />

double currentBalance = account.getBalance();<br />

if (currentBalance < amount) {<br />

throw new InsufficientBalanceException(accountId,<br />

currentBalance,amount);<br />

}<br />

account.setBalance(currentBalance - amount);<br />

accountDao.update(account);<br />

}<br />

/* Register account operation. */<br />

accountOperationDao.create(new AccountOperation(account,<br />

Calendar.getInstance(), AccountOperation.Type.WITHDRAW,<br />

amount));


AccountServiceImpl.java (3)<br />

@Transactional(readOnly = true)<br />

public AccountBlock findAccountsByUserId(Long userId,<br />

int startIn<strong>de</strong>x, int count) { ... }<br />

public void removeAccount(Long accountId)<br />

throws InstanceNotFoundException { ... }<br />

public void transfer(Long sourceAccountId,<br />

Long <strong>de</strong>stinationAccountId, double amount)<br />

throws InstanceNotFoundException,<br />

InsufficientBalanceException { ... }<br />

@Transactional(readOnly = true)<br />

public int getNumberOfAccountOperations(Long accountId,<br />

Calendar startDate, Calendar endDate)<br />

throws InstanceNotFoundException { ... }


AccountServiceImpl.java (y 4)<br />

@Transactional(readOnly = true)<br />

public List findAccountOperationsByDate(<br />

Long accountId, Calendar startDate, Calendar endDate,<br />

int startIn<strong>de</strong>x, int count)<br />

throws InstanceNotFoundException { ... }<br />

private List toAccountOperationInfos(<br />

List accountOperations) { ... }<br />

}


Transacciones <strong>con</strong> Anotaciones<br />

• Si se <strong>de</strong>sean utilizar anotaciones para <strong>de</strong>clarar las<br />

transacciones, el gestor <strong>de</strong> transacciones a utilizar se<br />

<strong>de</strong>clara a través <strong>de</strong> la etiqueta annotation-driven,<br />

perteneciente al espacio <strong>de</strong> nombres tx<br />

<br />

• El valor <strong>de</strong>l atributo transaction-manager indica<br />

el nombre <strong>de</strong>l bean que <strong>de</strong>be ser utilizado como<br />

gestor <strong>de</strong> transacciones<br />

• Este atributo es opcional, y si no está presente toma el valor<br />

por <strong>de</strong>fecto “transactionManager”<br />

• Por tanto en nuestro caso podríamos no haberlo<br />

especificado


Anotación @Transactional (1)<br />

• Pue<strong>de</strong> utilizarse para anotar una clase o un método <strong>con</strong>creto<br />

• En una clase se aplica a todos <strong>los</strong> métodos que <strong>con</strong>tiene<br />

• En un método sobrescribe el comportamiento especificado para la<br />

clase a la que pertenece<br />

• Propieda<strong>de</strong>s:<br />

• propagation:<br />

• PROPAGATION_REQUIRED (valor por <strong>de</strong>fecto): El método <strong>de</strong>be<br />

ejecutarse <strong>de</strong>ntro <strong>de</strong> una transacción; si ya existe una se ejecuta en<br />

esa y si no se crea una nueva<br />

• PROPAGATION_MANDATORY: Igual que el anterior pero la transacción<br />

<strong>de</strong>be existir (si no se lanza una excepción)<br />

• PROPAGATION_REQUIRES_NEW: El método <strong>de</strong>be ejecutarse <strong>de</strong>ntro <strong>de</strong><br />

una transacción nueva (si ya existe una se suspen<strong>de</strong> mientras)<br />

• PROPAGATION_NESTED: El método <strong>de</strong>be ejecutarse en una<br />

transacción anidada si ya existe una transacción en progreso. Si no<br />

existe se comporta igual que PROPAGATION_REQUIRED<br />

• PROPAGATION_NEVER: El método no <strong>de</strong>be ejecutarse <strong>de</strong>ntro <strong>de</strong> una<br />

transacción (si existe una en progreso se lanza una excepción)<br />

• PROPAGATION_NOT_SUPPORTED: Igual que el anterior pero si existe<br />

una transacción se suspen<strong>de</strong> en vez <strong>de</strong> lanzar una excepción<br />

• PROPAGATION_SUPPORTS: No es necesario que el método se ejecute<br />

<strong>de</strong>ntro <strong>de</strong> una transacción pero si ya existe una se ejecuta <strong>de</strong>ntro <strong>de</strong><br />

ella


Anotación @Transactional (2)<br />

• Propieda<strong>de</strong>s (<strong>con</strong>t.):<br />

• isolation: Nivel <strong>de</strong> aislamiento (por <strong>de</strong>fecto el <strong>de</strong> la<br />

plataforma)<br />

• ISOLATION_DEFAULT: El <strong>de</strong> la plataforma<br />

• ISOLATION_READ_UNCOMMITED: Pue<strong>de</strong>n ocurrir “dirty reads”,<br />

“non-repeatable reads” y “phamton reads”<br />

• ISOLATION_READ_COMMITED: Pue<strong>de</strong>n ocurrir “nonrepeatable<br />

reads” y “phamton reads”<br />

• ISOLATION_REPETEABLE_READ: Pue<strong>de</strong>n ocurrir “phamton<br />

reads”<br />

• ISOLATION_SERIALIZABLE: Elimina todos <strong>los</strong> problemas <strong>de</strong><br />

<strong>con</strong>currencia<br />

• readOnly: Lectura/escritura (<strong>de</strong>fecto) o solo lectura<br />

• Importante indicarlo para po<strong>de</strong>r hacer optimizaciones !!<br />

• timeout: Timeout <strong>de</strong> la transacción (por <strong>de</strong>fecto el <strong>de</strong> la<br />

plataforma)<br />

• Si el timeout expira entonces se hace un rollback <strong>de</strong> la<br />

transacción


Anotación @Transactional (y 3)<br />

• Por <strong>de</strong>fecto cualquier excepción <strong>de</strong> tipo “unchecked” (hija <strong>de</strong><br />

RuntimeException) provocará un rollback, y cualquier<br />

excepción “checked” (hija <strong>de</strong> Exception) no<br />

• Es posible modificar este comportamiento a través <strong>de</strong> propieda<strong>de</strong>s<br />

<strong>de</strong> la anotación @Transactional<br />

• rollbackFor/rollBackForClassName: Array <strong>de</strong> clases/nombres<br />

<strong>de</strong> excepciones que <strong>de</strong>ben causar un rollback<br />

• Ejemp<strong>los</strong>:<br />

@Transactional(rollbackFor={Exception1.class, Exception2.class})<br />

@Transactional(rollbackForClassName={"es.udc.Exception1", "es.udc.Exception2"})<br />

• noRollbackFor/noRollbackForClassName: Array <strong>de</strong><br />

clases/nombres <strong>de</strong> excepciones que no <strong>de</strong>ben causar un rollback<br />

• La utilizaremos en las fachadas <strong>de</strong>l mo<strong>de</strong>lo (servicios) para<br />

<strong>de</strong>clarar la transaccionalidad <strong>de</strong> sus métodos<br />

• Es posible anotar la interfaz que <strong>de</strong>clara las operaciones <strong>de</strong>l<br />

servicio, pero es más recomendable anotar la clase <strong>de</strong><br />

implementación <strong>de</strong>l servicio


Implementación <strong>de</strong> Fachadas (1)<br />

• Los casos <strong>de</strong> uso se implementan en términos <strong>de</strong><br />

DAOs (tal como se vio en el apartado 3.2)<br />

• En <strong>los</strong> DAOs se inyecta un objeto <strong>de</strong> tipo<br />

org.hibernate.SesionFactory proporcionado por<br />

<strong>Spring</strong><br />

• Los DAOs se inyectan en la clase <strong>de</strong> implementación <strong>de</strong> la<br />

Fachada<br />

• Se utiliza un mecanismo proporcionado por <strong>Spring</strong> para<br />

<strong>con</strong>vertir las excepciones <strong>de</strong> persistencia nativas a una<br />

jerarquía propia in<strong>de</strong>pendiente <strong>de</strong>l framework utilizado para<br />

la persistencia


Implementación <strong>de</strong> Fachadas (y 2)<br />

• Para indicar la transaccionalidad <strong>de</strong> <strong>los</strong> casos <strong>de</strong> uso<br />

utilizamos la anotación @Transactional sobre la<br />

clase <strong>de</strong> implementación <strong>de</strong> la Fachada<br />

• Se <strong>de</strong>clara un gestor <strong>de</strong> transacciones que <strong>de</strong>lega en el<br />

gestor <strong>de</strong> transacciones <strong>de</strong> Hibernate<br />

• Se le inyecta el mismo SesionFactory que el creado para<br />

inyectar en <strong>los</strong> DAOs para que pueda acce<strong>de</strong>r a través <strong>de</strong> él al<br />

gestor <strong>de</strong> transacciones <strong>de</strong> Hibernate<br />

• Se le inyecta un DataSource que se recupera vía JNDI<br />

(proporcionado por el <strong>con</strong>tenedor <strong>de</strong> aplicaciones)<br />

• La implementación <strong>de</strong> las Fachadas es in<strong>de</strong>pendiente<br />

<strong>de</strong>l software utilizado para el acceso a datos (en<br />

nuestro caso Hibernate)

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!