Sei sulla pagina 1di 62

3.

4 Implementacin de los Casos de Uso con Spring

ndice

Introduccin a Spring Declaracin y Configuracin de beans Excepciones de Persistencia Declaracin de DataSources Integracin con Hibernate 3 Gestin de Transacciones

Qu es Spring? (1)

Framework de cdigo abierto creado por Rod Johnson

http://www.springframework.org

Motivacin: Facilitar el desarrollo de aplicaciones Java EE, promoviendo buenas prcticas de diseo y programacin

Simplifica el uso de muchas de las APIs de Java EE Dispone de alternativas a algunas de las APIs de Java EE

Internamente se apoyan en APIs de Java EE de ms bajo nivel

Facilita el uso de patrones de diseo ampliamente reconocidos dentro de la industria del desarrollo de software (Factory, Abstract Factory, Builder, Decorator, Service Locator, etc.) Es modular: es posible usar algunos de los mdulos sin comprometerse con el uso del resto

Soporte para capa modelo e interfaz Web

Qu es Spring? (y 2)

Nosotros utilizaremos el soporte de Spring para implementar casos de uso a nivel de capa modelo

Alternativa al uso de los Session Bean de EJB

Puede actuar como una capa de integracin entre diferentes APIs (JDBC, JNDI, etc.) y frameworks

En nuestro caso entre Tapestry e Hibernate

Conceptos Bsicos en Spring

Inyeccin de dependencias (Dependency Injection, DI) Programacin orientada a aspectos (Aspect-Oriented Programming, AOP)

Inyeccin de Dependencias

Tradicionalmente cada objeto es responsable de obtener sus propias referencias a los objetos con los que colabora Cuando se aplica la Inyeccin de dependencias (DI), alguna entidad externa es la responsable de proporcionar a un objeto sus dependencias cuando se crea el objeto (las dependencias se inyectan en el objeto) Ventajas

Prdida de acoplamiento entre los objetos

Si un objeto conoce sus dependencias a travs de interfaces, es posible cambiar la implementacin de esas dependencias transparentemente para el objeto que las contiene

Programacin Orientada a Aspectos (AOP)

Tcnica de programacin que promueve la separacin de funcionalidades

AOP: http://en.wikipedia.org/wiki/Aspect-oriented_programming

Algunos servicios son utilizados repetidas veces en diferentes componentes de un sistema, cuya responsabilidad principal es otra

E.g. servicios de logging o gestin de transacciones y seguridad Se conocen como aspectos transversales ("cross cutting concerns)

Un framework de AOP hace posible modularizar estos aspectos o servicios y aplicarlos declarativamente a los componentes que los precisen

Cada aspecto se implementa en un nico punto Declarativamente se especifican los mtodos que el framework tiene que interceptar para aplicarles el o los aspectos que el desarrollador desea Cada componente debe preocuparse nicamente de su funcionalidad principal sin preocuparse de los servicios del sistema que precise

Mdulos/Paquetes (1)
ORM
Spring Web MVC Framework Integration Struts WebWork Tapestry JSF Rich View Support JSPs Velocity FreeMarker PDF Jasper Reports Excel Spring Portlet MVC

Web

Spring JDBC Transaction management

DAO

Hibernate JPA JDO TopLink OJB iBatis

Spring AOP Integracin AspectJ

AOP

JMX JMS JCA Remotig EJBs Email

JEE

IoC Container

Core

Mdulos/Paquetes (2)

Core

Constituye la parte fundamental del framework y proporciona la caracterstica de Inyeccin de Dependencias (DI) / Inversin de Control (IoC) Proporciona una implementacin sofisticada del patrn Factora que permite desacoplar la configuracin y especificacin de dependencias de la lgica de la aplicacin Proporciona una capa de abstraccin sobre JDBC que elimina la necesidad de codificar y analizar los cdigos de error especficos de cada BBDD Tambin proporciona una manera de gestionar transacciones tanto programtica como declarativamente, no slo para clases que implementen ciertas interfaces, sino para cualquier objeto Java (POJO)

DAO

Mdulos/Paquetes (y 3)

ORM

Proporciona capas de integracin para las APIs de mapeadores objeto-relacionales ms populares: Hibernate, JPA, JDO, iBatis Utilizando este paquete es posible utilizar cualquiera de estos mapeadores objeto-relacionales en combinacin con las dems caractersticas que ofrece Spring (como por ejemplo con la gestin declarativa de transacciones) Proporciona una implementacin del paradigma de la programacin orientada a aspectos (conforme a la AOP Alliance), que es utilizada, transparentemente para el programador, por otros paquetes de Spring, pero que tambin puede ser usada directamente

AOP

El Contenedor (1)

El contenedor de IoC es el ncleo del sistema


Responsable de la creacin y configuracin de los Beans Nota: Un bean, en el contexto de Spring, es un POJO que es creado y manejado por el contenedor de IoC

La interfaz BeanFactory o su hija ApplicationContext representan la interfaz del contenedor

Spring proporciona varias implementaciones

El Contenedor (2)

Instanciacin
try {
ApplicationContext ctx = new ClassPathXmlApplicationContext( new String[] {SPRING_CONFIG_FILE, SPRING_CONFIG_TEST_FILE}); AccountService accountService = (AccountService) ctx.getBean("accountService"); ... } catch (Exception e) { e.printStackTrace(); }

El Contenedor (y 3)

ClassPathXmlApplicationContext

Permite declarar los objetos que componen la aplicacin, y las dependencias entre ellos en XML A partir de los metadatos de configuracin en XML es capaz de crear y configurar los objetos que componen la aplicacin A travs del mtodo getBean es posible obtener referencias a los objetos declarados, a partir de su nombre

Declaracin de Beans en XML (1)


<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost/pojo" p:username="pojo" p:password="pojo" /> <bean id="accountService" class="es.udc.pojo.minibank.model.accountservice.AccountServiceImpl" p:accountDao-ref="accountDao" p:accountOperationDao-ref="accountOperationDao" />

Es equivalente a
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost/pojo" /> <property name="username" value="pojo" /> <property name="password" value="pojo" /> </bean> <bean id="accountService" class="es.udc.pojo.minibank.model.accountservice.AccountServiceImpl" <property name="accountDao" ref="accountDao" /> <property name="accountOperationDao" ref="accountOperationDao" /> </bean>

Declaracin de Beans en XML (2)


Se declaran con la etiqueta bean Parmetros bsicos


id: Nombre o identificador del bean class: Clase de implementacin del bean Permite inyectar valores u otros beans (a travs de referencias), invocando al mtodo set correspondiente del bean sobre el que se est realizando la inyeccin

Inyeccin de dependencias basada en setters

Se indica el nombre de la propiedad que se desea inyectar y el valor que se le desea proporcionar

Declaracin de Beans en XML (y 3)

Inyeccin de dependencias basada en setters (cont)

Es posible especificarlas

A travs de un elemento anidado property, que acepta los siguientes atributos


name: Nombre de la propiedad donde se desea inyectar el valor value: Para inyectar un valor constante ref: Para inyectar otro bean a partir de su nombre

Con sintaxis abreviada (utilizando el espacio de nombres p) a travs de los atributos

p:nombrePropiedad: Para inyectar un valor constante en la propiedad indicada p:nombrePropiedad-ref: Para inyectar otro bean a partir de su nombre en la propiedad indicada

El bean se crea a partir de su constructor vaco y a continuacin se invocan los mtodos set con los valores adecuados

Declaracin de Beans Usando Anotaciones (1)


@Repository("accountDao") public class AccountDaoHibernate extends GenericDaoHibernate<Account, Long> implements AccountDao { ... } @Repository("accountOperationDao") public class AccountOperationDaoHibernate extends GenericDaoHibernate<AccountOperation, Long> implements AccountOperationDao { ... } @Service("accountService") public class AccountServiceImpl implements AccountService { ... }

Declaracin de Beans Usando Anotaciones (2)

Spring proporciona un mecanismo para detectar automticamente clases anotadas y registrarlas como beans en el ApplicationContext

Se puede utilizar la anotacin genrica @Component sobre cualquier clase, o sus especializaciones @Repository, @Service y @Controller para anotar clases en las capas de persistencia, servicios y vista respectivamente

La documentacin de Spring aconseja utilizar las especializaciones porque otros frameworks o herramientas pueden aplicarles semntica especial y el propio Spring puede aadrsela en futuras versiones Si la anotacin contiene el atributo name, entonces el valor de ese atributo ser el que d nombre al bean; en otro caso, se le dar el mismo nombre que la clase pero empezando por minscula

Declaracin de Beans Usando Anotaciones (y 3)

Spring proporciona un mecanismo para detectar automticamente clases anotadas y registrarlas como beans en el ApplicationContext (cont)

Adems debe utilizarse el tag component-scan en el fichero de configuracin de Spring indicando en el atributo base-package el o los paquetes (separados por comas) que incluyen las clases anotadas (puede ser un paquete padre, no es necesario que sean los paquetes que contienen las clases directamente)

<beans xmlns="http://www.springframework.org/schema/beans" ... xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="... "> ... <context:component-scan base-package="es.udc.pojo.minibank.model"/> ... </beans>

Auto-inyeccin de Dependencias

El contenedor de Spring es capaz de auto-inyectar dependencias entre beans segn diferentes criterios

Cuando se usan metadatos de configuracin en XML, la autoinyeccin de dependencias se especifica a travs del atributo autowire de la etiqueta <bean/> Tambin es posible realizar auto-inyeccin de dependencias utilizando la anotacin @Autowired

Por tipo: Busca un bean con el mismo tipo que la propiedad Por nombre: Busca un bean con el mismo id que la propiedad Por constructor: Busca uno o ms beans cuyos tipos coincidan con los parmetros de uno de los constructores de ese bean

Ventajas

Desventajas

La cantidad de configuracin necesaria puede verse reducida significativamente, y tambin las necesidades de cambios en dicha configuracin segn avanza el desarrollo Las relaciones entre los beans dejan de estar documentadas explcitamente Si hay varios beans con el mismo tipo no puede utilizarse la autoinyeccin por tipo (que es la que suele utilizarse)

Auto-Inyeccin de Dependencias Usando Anotaciones (1)

@Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Autowired private AccountOperationDao accountOperationDao; ... }

Auto-Inyeccin de Dependencias Usando Anotaciones (y 2)

La anotacin @Autowired puede ser aplicada a setters, pero tambin a mtodos con nombres arbitrarios y mltiples argumentos, a constructores y a propiedades Por defecto la auto-inyeccin se realiza por tipo y si no hay ningn bean que la satisfaga entonces se produce un error Para poder utilizar esta anotacin es necesario especificar la etiqueta annotation-config en el fichero de configuracin de Spring
<beans xmlns="http://www.springframework.org/schema/beans" ... xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="... "> ... <context:annotation-config/> ... </beans>

Beans de la capa modelo de MiniBank (pojo-minibank-spring-config.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" ... xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="...">

<!-- Enable usage of @Autowired. --> <context:annotation-config/>


<!-- Enable component scanning for defining beans with annotations. --> <context:component-scan base-package="es.udc.pojo.minibank.model"/> ... <!-- Hibernate Session Factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" ... />

... </beans>

AccountServiceImpl.java
@Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Autowired private AccountOperationDao accountOperationDao; ... }

AccountDaoHibernate.java y AccountOperationDaoHibernate.java
@Repository("accountDao") public class AccountDaoHibernate extends GenericDaoHibernate<Account, Long> implements AccountDao { ... }

@Repository("accountOperationDao") public class AccountOperationDaoHibernate extends GenericDaoHibernate<AccountOperation, Long> implements AccountOperationDao { ...

GenericDaoHibernate.java
public class GenericDaoHibernate<E, PK extends Serializable> implements GenericDao<E, PK> { private SessionFactory sessionFactory; ... @Autowired public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } ... }

Beans de la capa modelo de MiniBank

Declaracin:

Se declaran los siguientes beans de usuario mediante anotaciones


Un bean para cada DAO de Hibernate Un bean para la implementacin del servicio

Se declara un bean en XML para la SessionFactory (que usan los DAOs de Hibernate)

Inyeccin de dependencias

Las dependencias entre los beans se auto-inyectan mediante anotaciones La implementacin del servicio usa los DAOs

Se inyectan directamente sobre las propiedades privadas que los referencian y por tanto no son necesarios los setters Se inyecta en GenericDaoHibernate sobre el setter correspondiente (el setter es necesario ya que es invocado desde las clases de prueba)

Los DAOs usan la SessionFactory

Beans: Inyeccin de Dependencias


accountDao
AccountDaoHibernate - sessionFactory : SessionFactory

accountService
AccountServiceImpl
- accountDao : AccountDao - accountOperationDao : AccountOperationDao

sessionFactory

accountOperationDao
AccountOperationDaoHibernate - sessionFactory : SessionFactory

mbito de los Beans

El mbito de un bean se especifica a travs del atributo scope de la etiqueta bean o a travs de la anotacin @Scope (segn se use configuracin XML o basada en anotaciones) Algunos posibles valores son:

singleton (valor por defecto)

El contenedor usa siempre la misma instancia (ya sea cuando se le pide a travs de la API o cuando necesita inyectarlo) Indica que el contenedor debe crear una nueva instancia del bean cada vez que se precise una Puede ser necesario, por ejemplo, si el bean tiene estado

prototype

OJO con los beans de tipo singleton con dependencias con beans de tipo prototype

Ms sobre Declaracin de Beans

Otras funcionalidades que ofrece Spring


Instanciacin de beans a partir de factoras Inyeccin de dependencias a travs de constructores

Los valores o referencias a otros beans se inyectan a travs de los argumentos de un constructor

Inyeccin de propiedades multivaluadas (arrays, listas, conjuntos, mapas) Inicializacin y liberacin de recursos de un bean a travs de mtodos que deben ser invocados justo despus de haberse creado y justo antes de ser destruido, respectivamente ...

Excepciones de Persistencia (1)

En JDBC se lanza la excepcin java.sql.SQLException cuando se produce cualquier tipo de error en el acceso a los datos

Problema: Hay que capturarla siempre y analizarla para saber de qu tipo de error se trata

Algunos frameworks (e.g. Hibernate) ofrecen una jerarqua de excepciones ms descriptiva (una excepcin diferente para cada tipo de error)

Ventaja: Permite diferenciar entre qu tipos de errores capturar Problema: Son especficas del framework utilizado para realizar la persistencia de los datos

Excepciones de Persistencia (2)


public class GenericDaoHibernate<E, PK extends Serializable> implements GenericDao<E, PK> { ... protected DataAccessException convertHibernateAccessException( HibernateException e) { return SessionFactoryUtils.convertHibernateAccessException(e); } public void save(E entity) { try { getSession().saveOrUpdate(entity); } catch (HibernateException e) { throw convertHibernateAccessException(e); } } ... }

Excepciones de Persistencia (3)


@Repository("accountDao") public class AccountDaoHibernate extends GenericDaoHibernate<Account, Long> implements AccountDao { @SuppressWarnings("unchecked") public List<Account> findByUserId(Long userId, int startIndex, int count) { try { return getSession().createQuery( "SELECT a FROM Account a WHERE a.userId = :userId " + "ORDER BY a.accountId"). setParameter("userId", userId). setFirstResult(startIndex). setMaxResults(count).list();

} catch (HibernateException e) { throw convertHibernateAccessException(e); }


} }

Excepciones de Persistencia (y 4)

Spring proporciona una jerarqua de excepciones de acceso a datos (heredan de DataAccessException) que resuelve ambos problemas

Cada excepcin representa un error concreto No son especficas del framework de persistencia de datos utilizado, que por tanto se oculta a las capas superiores Son excepciones unchecked

Spring proporciona mecanismos para realizar la conversin entre las excepciones nativas del framework de persistencia utilizado y la jerarqua propia

El mtodo convertHibernateAccessException de la clase SessionFactoryUtils realiza esta conversin para el caso de Hibernate Se ha creado un mtodo protegido en el DAO genrico para realizar la conversin En todos los mtodos de los DAOs (incluidos los del DAO genrico) se captura HibernateException y se lanza hacia las capas superiores el resultado de convertirla a una excepcin de la jerarqua de DataAccessException

DataSources

Independientemente del framework de persistencia utilizado probablemente se necesitar configurar una referencia a un DataSource Spring proporciona, entre otras, las siguientes opciones para configurar un bean de tipo DataSource

DataSources definidos directamente sobre un driver JDBC


SingleConnectionDataSource DriverMangerDataSource Cualquier contenedor Java EE puede poner accesible va JNDI un DataSource (que normalmente implementar pool de conexiones)

DataSources que son localizados va JNDI

SingleConnectionDataSource

Cuando se crea, solicita una conexin a la base de datos El mtodo getConnection siempre devuelve esa conexin (o un proxy)

Es usual especificar suppressClose="true" para que devuelva un proxy de la conexin cuyo mtodo close (el del proxy) no cierra la conexin Un DataSource con estas caractersticas es suficiente y eficiente para los tests de integracin

Este DataSource slo es vlido para entornos single-thread

Adems, hay que indicar tambin las siguientes propiedades


Suficiente: llega con disponer de una conexin Eficiente: la conexin a la base de datos slo se pide cuando se crea el DataSource El nombre de la clase del driver JDBC La URL de conexin a la BD El usuario para conectarse a la BD La contrasea del usuario indicado

<bean id="dataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost/pojotest" p:username="pojo" p:password="pojo" p:suppressClose="true" />

DriverMangerDataSource

Implementacin simple de la interfaz DataSource


No implementa pool de conexiones El mtodo getConnection devuelve una conexin nueva cada vez que es invocado Vlido para entornos multi-thread

Un DataSource con estas caractersticas es suficientemente eficiente y seguro para probar una aplicacin Web a nivel de usuario Hay que indicar las siguientes propiedades

El nombre de la clase del driver JDBC La URL de conexin a la BD El usuario para conectarse a la BD La contrasea del usuario indicado

Es el que usamos con el plugin de Jetty para Maven (src/main/jetty/jetty-env.xml)

Acceso a DataSources mediante JNDI (1)

JNDI (Java Naming and Directory Interface)


Familia de paquetes javax.naming (Java SE) Es una API que abstrae el acceso a un servicio de nombres y directorios (e.g. LDAP) Es posible registrar objetos mediante un nombre jerrquico

Los servidores de aplicaciones Java EE exponen diversos objetos mediante JNDI Los servidores de aplicaciones Java EE proporcionan implementaciones de DataSource

Cada objeto DataSource es accesible a partir de un nombre JNDI de la forma java:comp/env/XXX/YYY, donde XXX suele (recomendado) ser "jdbc" e YYY el nombre de un DataSource concreto Habitualmente estos objetos DataSource implementan la estrategia de pool de conexiones Requiere configuracin en el servidor (driver, URL, usuario, contrasea, parmetros especficos al pool, etc.)

Ej.: En Tomcat se definen en conf/server.xml

Acceso a DataSources mediante JNDI (y 2)


<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" p:jndiName="jdbc/pojo-examples-ds" p:resourceRef="true" />

El atributo jndiName se utiliza para indicar el nombre del recurso accesible va JNDI Si la aplicacin est ejecutndose dentro de un servidor de aplicaciones Java EE

El valor del atributo resourceRef debe ser true El nombre indicado en jndiName es relativo al contexto java:comp/env/

JndiObjectFactoryBean implementa org.springframework.beans.factory.FactoryBean

Los beans que implementan esta interfaz se definen igual que el resto de beans, pero cuando se referencian desde otros beans no se inyecta una instancia de ese tipo sino el objeto que devuelve su mtodo getObject El mtodo getObject de JndiObjectFactoryBean devuelve el objeto asociado al nombre JNDI especificado en la configuracin

Integracin con Hibernate 3 (1)

Los DAOs implementados con Hibernate necesitan un objeto de tipo org.hibernate.SessionFactory del que obtener la sesin actual

La siguiente declaracin permite definir un bean para obtener un SessionFactory que utiliza las anotaciones de Hibernate en las entidades

Como veremos ms adelante, el gestor de transacciones de Hibernate tambin precisa un objeto de ese tipo

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" p:dataSource-ref="dataSource" p:configLocation="classpath:/pojo-minibank-hibernate-config.xml"/>

datasource: indica el nombre de un bean de tipo DataSource (para obtener las conexiones a la BD) configLocation: Indica donde est el fichero de configuracin de Hibernate (fichero llamado pojo-minibank-hibernateconfig.xml localizado en el classpath de ejecucin) AnnotationSessionFactoryBean es un FactoryBean (igual que la clase JndiObjectFactoryBean explicada en la transparencia anterior) cuyo mtodo getObject devuelve una instancia que implementa SessionFactory

Integracin con Hibernate 3 (y 2)

Como ya hemos visto con anterioridad el bean sessionFactory se inyecta en el DAO genrico

public class GenericDaoHibernate<E, PK extends Serializable> implements GenericDao<E, PK> { private SessionFactory sessionFactory; ... @Autowired public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } ... }

Transacciones

Spring no gestiona directamente las transacciones, sino que lo hace a travs de una abstraccin (patrn Strategy)

Interfaz
org.springframework.transaction.PlatformTransactionManager

Se puede trabajar con las transacciones independientemente de la implementacin del gestor de transacciones concreto que se est utilizando

Spring proporciona una serie de gestores de transacciones que delegan la responsabilidad de la gestin de las transacciones a implementaciones especficas de la plataforma utilizada Se puede trabajar con transacciones a travs de la API Java de Spring, pero tambin se pueden definir de forma declarativa haciendo uso del framework AOP de Spring, que incluye una implementacin del aspecto de transaccionalidad

Es posible hacerlo mediante XML o mediante anotaciones Java Utilizaremos la opcin de las anotaciones porque simplifica la declaracin de las transacciones

Transacciones con Hibernate 3

Si la capa de persistencia del modelo est implementada con Hibernate, entonces el gestor de transacciones a utilizar es el siguiente

<bean id="transactionManager class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" />

Es preciso inyectarle un objeto SessionFactory de Hibernate

Ya hemos declarado uno para utilizar en los DAOs

HibernateTransactionManager delega la gestin de las transacciones a un objeto org.hibernate.Transaction


A partir del objeto SessionFactory obtiene la sesin Hibernate A partir de la sesin Hibernate obtiene el objeto Transaction

API Transacciones (1)


public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }

public interface TransactionStatus { boolean isNewTransaction(); void setRollbackOnly(); boolean isRollbackOnly(); }

API Transacciones (y 2)

Un gestor de transacciones implementa la interfaz PlatformTransactionManager

TransactionException es una excepcin unchecked El mtodo getTransaction devuelve un objeto de tipo TransactionStatus en funcin de un parmetro de tipo TransactionDefinition

TransactionStatus representa una transaccin

Puede ser la transaccin actual o una nueva

TransactionDefinition es una interfaz a travs de la cual se pueden especificar las caractersticas de la transaccin que se quiere obtener (propagacin, nivel de aislamiento, timeout, propiedad read-only)

La subinterfaz TransactionAttribute permite, adems, especificar la lista de excepciones que provocan o no un rollback Si se pasa null en getTransaction, se utilizan los valores por defecto

Los mtodos commit y rollback se utilizan para hacer un commit o un rollback de la transaccin que se les pasa

AOP: Gestin de Transacciones (1)


@Service("accountService") public class AccountServiceImpl implements AccountService {
@Autowired private PlatformTransactionManager transactionManager; @Autowired private AccountDao accountDao; @Autowired private AccountOperationDao accountOperationDao;

AOP: Gestin de Transacciones (2)


public Account createAccount(Account account) { TransactionStatus transactionStatus = transactionManager.getTransaction(null); try { accountDao.save(account); } catch (RuntimeException e) { transactionManager.rollback(transactionStatus); throw e; } transactionManager.commit(transactionStatus); return account; }

Iniciar transaccin

Finalizar transaccin

AOP: Gestin de Transacciones (3)


public void removeAccount(Long accountId) throws InstanceNotFoundException { TransactionStatus transactionStatus = transactionManager.getTransaction(null); try { accountDao.remove(accountId); accountOperationDao.removeByAccountId(accountId); } catch (RuntimeException e) { transactionManager.rollback(transactionStatus); throw e; } catch (InstanceNotFoundException e) { transactionManager.commit(transactionStatus); throw e; } transactionManager.commit(transactionStatus); }

Iniciar transaccin

Finalizar transaccin

AOP: Gestin de Transacciones (4)


public void withdrawFromAccount(Long accountId, double amount) throws InstanceNotFoundException, InsufficientBalanceException { TransactionStatus transactionStatus = transactionManager.getTransaction(null); try { /* Find account. */ Account account = accountDao.find(accountId); /* Modify balance. */ double currentBalance = account.getBalance(); if (currentBalance < amount) { throw new InsufficientBalanceException(accountId, currentBalance,amount); } account.setBalance(currentBalance - amount);

Iniciar transaccin

AOP: Gestin de Transacciones (5)


/* Register account operation. */ accountOperationDao.save(new AccountOperation(account, Calendar.getInstance(), AccountOperation.Type.WITHDRAW, amount)); } catch (RuntimeException e) { transactionManager.rollback(transactionStatus); throw e; } catch (InstanceNotFoundException e) { transactionManager.commit(transactionStatus); throw e; } catch (InsufficientBalanceException e) { transactionManager.commit(transactionStatus); throw e; } transactionManager.commit(transactionStatus); } ... }

Finalizar transaccin

AOP: Gestin de Transacciones (6)

El cdigo para todos los casos de uso transaccionales es similar:

Iniciar la transaccin (con las propiedades adecuadas) a partir del gestor de transacciones utilizad Ejecutar la lgica propia del caso de uso Finalizar transaccin (commit o rollback) en funcin de si se ha producido alguna excepcin o no y de su tipo

El cdigo comn para la gestin de las transacciones puede eliminarse de la implementacin de todos los casos de uso que lo precisen, y declarativamente decir cundo debe ejecutarse

AOP: Gestin de Transacciones (y 7)

Declarativamente es posible indicar


El gestor de transacciones a utilizar Que los mtodos createAccount, removeAccount, withdrawFromAccount y todos los dems de la clase AccountServiceImpl son transaccionales Spring intercepta las invocaciones a los mtodos declarados como transaccionales:

[Antes de que se ejecute el mtodo] Ejecuta el cdigo necesario para comenzar la transaccin

Declarativamente pueden indicarse parmetros como, por ejemplo, el nivel de aislamiento deseado para la transaccin

[Despus de que se ejecute el mtodo] Ejecuta el cdigo necesario para finalizar la transaccin (ya sea con un commit o un rollback)

Pueden indicarse qu excepciones deben provocar un rollback y cuales no

AccountServiceImpl.java (1)
@Service("accountService") @Transactional public class AccountServiceImpl implements AccountService {

@Autowired private AccountDao accountDao;


@Autowired private AccountOperationDao accountOperationDao; public Account createAccount(Account account) { ... } @Transactional(readOnly = true) public Account findAccount(Long accountId) throws InstanceNotFoundException { ... } public void addToAccount(Long accountId, double amount) throws InstanceNotFoundException { ... }

AccountServiceImpl.java (2)
public void withdrawFromAccount(Long accountId, double amount) throws InstanceNotFoundException, InsufficientBalanceException { /* Find account. */ Account account = accountDao.find(accountId); /* Modify balance. */ double currentBalance = account.getBalance(); if (currentBalance < amount) { throw new InsufficientBalanceException(accountId, currentBalance,amount); } account.setBalance(currentBalance - amount); /* Register account operation. */ accountOperationDao.save(new AccountOperation(account, Calendar.getInstance(), AccountOperation.Type.WITHDRAW, amount)); }

AccountServiceImpl.java (3)
@Transactional(readOnly = true) public AccountBlock findAccountsByUserId(Long userId, int startIndex, int count) { ... }

public void removeAccount(Long accountId) throws InstanceNotFoundException { ... }


public void transfer(Long sourceAccountId, Long destinationAccountId, double amount) throws InstanceNotFoundException, InsufficientBalanceException { ... } @Transactional(readOnly = true) public int getNumberOfAccountOperations(Long accountId, Calendar startDate, Calendar endDate) throws InstanceNotFoundException { ... }

@Transactional(readOnly = true) public List<AccountOperation> findAccountOperationsByDate( Long accountId, Calendar startDate, Calendar endDate, int startIndex, int count) throws InstanceNotFoundException { ... }
}

Transacciones con Anotaciones

Si se desean utilizar anotaciones para declarar las transacciones, el gestor de transacciones a utilizar se declara a travs de la etiqueta annotation-driven, perteneciente al espacio de nombres tx
<tx:annotation-driven transaction-manager="transactionManager" />

El valor del atributo transaction-manager indica el nombre del bean que debe ser utilizado como gestor de transacciones

Este atributo es opcional, y si no est presente toma el valor por defecto transactionManager Por tanto en nuestro caso podramos no haberlo especificado

Anotacin @Transactional (1)

Puede utilizarse para anotar una clase o un mtodo concreto


Propiedades:

En una clase se aplica a todos los mtodos que contiene En un mtodo sobrescribe el comportamiento especificado para la clase a la que pertenece propagation:

PROPAGATION_REQUIRED (valor por defecto): El mtodo debe ejecutarse dentro de una transaccin; si ya existe una, se ejecuta en esa, y si no, se crea una nueva PROPAGATION_MANDATORY: Igual que el anterior pero la transaccin debe existir (si no se lanza una excepcin) PROPAGATION_REQUIRES_NEW: El mtodo debe ejecutarse dentro de una transaccin nueva (si ya existe una se suspende mientras) PROPAGATION_NESTED: El mtodo debe ejecutarse en una transaccin anidada si ya existe una transaccin en progreso. Si no existe se comporta igual que PROPAGATION_REQUIRED PROPAGATION_NEVER: El mtodo no debe ejecutarse dentro de una transaccin (si existe una en progreso se lanza una excepcin) PROPAGATION_NOT_SUPPORTED: Igual que el anterior pero si existe una transaccin se suspende en vez de lanzar una excepcin PROPAGATION_SUPPORTS: No es necesario que el mtodo se ejecute dentro de una transaccin pero si ya existe una se ejecuta dentro de ella

Anotacin @Transactional (2)

Propiedades (cont.):

isolation: Nivel de aislamiento (por defecto el de la plataforma)


ISOLATION_DEFAULT: El de la plataforma ISOLATION_READ_UNCOMMITED: Pueden ocurrir dirty reads, non-repeatable reads y phanton reads ISOLATION_READ_COMMITED: Pueden ocurrir nonrepeatable reads y phamton reads ISOLATION_REPETEABLE_READ: Pueden ocurrir phanton reads ISOLATION_SERIALIZABLE: Elimina todos los problemas de concurrencia
Importante indicarlo para poder hacer optimizaciones !!

readOnly: Lectura/escritura (defecto) o solo lectura

timeout: Timeout de la transaccin (por defecto el de la plataforma)

Si el timeout expira entonces se hace un rollback de la transaccin

Anotacin @Transactional (y 3)

Por defecto cualquier excepcin de tipo unchecked (hija de RuntimeException) provocar un rollback, y cualquier excepcin checked (hija de Exception) no

Es posible modificar este comportamiento a travs de propiedades de la anotacin @Transactional

rollbackFor/rollBackForClassName: Array de clases/nombres de excepciones que deben causar un rollback

Ejemplos:

@Transactional(rollbackFor={Exception1.class, Exception2.class}) @Transactional(rollbackForClassName={"es.udc.Exception1", "es.udc.Exception2"})

noRollbackFor/noRollbackForClassName: Array de clases/nombres de excepciones que no deben causar un rollback

La utilizaremos en los servicios del modelo para declarar la transaccionalidad de sus mtodos

Es posible anotar la interfaz que declara las operaciones del servicio, pero es ms recomendable anotar la clase de implementacin del servicio

Invocacin de casos de uso


Clase Paquete es.udc.pojo.minibank.test.experiments.spring Ilustra cmo obtener una referencia a un servicio implementado con Spring y llamar a un caso de uso
... try { /* Get service object. */ ApplicationContext ctx = new ClassPathXmlApplicationContext( new String[] {SPRING_CONFIG_FILE, SPRING_CONFIG_TEST_FILE}); AccountService accountService = (AccountService) ctx .getBean("accountService"); accountService.withdrawFromAccount(accountId, amount); } catch (InstanceNotFoundException e) { e.printStackTrace(); } catch (InsufficientBalanceException e) { e.printStackTrace(); } ...

Implementacin de Servicios (1)

Los casos de uso se implementan en trminos de DAOs (tal como se vio en el apartado 3.2)

En los DAOs se inyecta un objeto de tipo org.hibernate.SessionFactory proporcionado por Spring Los DAOs se inyectan en la clase de implementacin de la Fachada Se utiliza un mecanismo proporcionado por Spring para convertir las excepciones de persistencia nativas a una jerarqua propia, independiente del framework utilizado para la persistencia

Implementacin de Servicios (y 2)

Para indicar la transaccionalidad de los casos de uso utilizamos la anotacin @Transactional sobre la clase de implementacin del Servicio

Se declara un gestor de transacciones que delega en el gestor de transacciones de Hibernate

Se le inyecta el mismo SessionFactory que el creado para inyectar en los DAOs, para que pueda acceder a travs de l al gestor de transacciones de Hibernate Se le inyecta un DataSource

La implementacin de los Servicios es independiente del software utilizado para el acceso a datos (en nuestro caso Hibernate)

Potrebbero piacerti anche