Publica tu how-to

Dinos como hacer lo que sabes hacer, mándanos un email a wdonet@gmail.com y lo publicamos (dos días máximo) o si te interesa unirte al equipo de redactores, también háznoslo saber por correo.

Configurar la capa de servicios como transaccionales con spring aop

Existen diversos conceptos que ya voy a dar por conocidos en esta publicación como lo son un advice, un target, un pointcut, un advisor y un aspecto, entre otros. Pero pueden conocer mas en la documentación de referencia sobre aop de Spring (inglés).

http://static.springsource.org/spring/docs/2.5.x/reference/images/tx.png
Conceptualmente una transacción luce como la imagen aqui arriba pero vamos a describir un poco mas el detalle.

Primeramente necesitamos la dependencia de spring-aspects, considerando que nuestro proyecto sea maven, debemos agregar a nuestro pom.xml la siguiente dependencia (por ahora usaremos la ón 2.5.6):
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-aspects</artifactid>
<version>2.5.6</version>
</dependency>


Basicamente necesitamos configurar tres elementos, (1) el manejador de las transacciones y su fuente de datos o DataSource, (2) un advice que es el código a ejecutar antes y/o despues de una petición a la base de datos punto central para iniciar-propagar-terminar una transaccion, y finalmente (3) un advisor, que es la relación de dicho advice con un pointcut.



1.- Manejador de transacciones (TransactionManager)
Como nuestro manejador de transacciones requiere de una fuente de datos vamos a configurarla con un driver de mysql de la siguiente forma de momento pues no abundaremos en la configuracion del datasource:
<bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/miBaseDatos"/>
<property name="username" value="user_sa"/>
<property name="password" value="mipass_sa"/>
</bean>


Luego necesitamos escoger una estrategia de transaccionalidad que implemente la interface de spring org.springframework.transaction.PlatformTransactionManager, y dado que usaremos MySQL en este caso, escogemos: DataSourceTransactionManager

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="basicDataSource"/>
</bean>


2.- Advice
Lo que sigue es configurar el advice o la forma en que se va a manejar la transaccionalidad, para ello necesitamos agregar el esquema y el esquema location de transaccion a nuestro tag del archivo de configuración de contexto de Spring:

Luego necesitamos usar el esquema tx:advice para crear nuestro advice y hacer referencia a nuestro bean con el manejador de transacciones (txManager), indicamos con tx:attributes la semántica que define en qué métodos (tx:method) van a ser considerados para iniciar/propagar una transacción y configurar el tipo de transacción.

<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- todos los metodos que inicien con get van a ser de solo lectura -->
<tx:method name="get*" read-only="true"/>
<!-- todos los metodos que inicien con guardar van a ejecutar rollback si se lanza alguna error de estos tipos-->
<tx:method name="guardar*" rollback-for="java.sql.SQLException, x.y.MiInfraestructuraException"/>
<!-- cualquier otro metodo usara la configuracion por defecto de una transaccion-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

Ojo: si tu bean manejador de transacciones ya se llama "transactionManager", puedes omitir la propiedad transaction-manager de tx:advice.

Es importante mencionar que por definición, Spring realiza rollback si encuentra que fue lanzada una Exception que herede de RuntimeException (osea no checadas) y las que listemos mediante la propiedad rollback-for. Esta propiedad nos ayuda a identificar las excepciones de negocio propias que deben provocar un rollback en la base de datos.

3.- Advisor y Pointcut
Finalmente vamos a asegurarnos que el comportamiento que acabamos de definir para nuestras transacciones sea ejecutado para cualquier operación definida mediante un aop:pointcut, para eso usamos un advisor. Agregamos el esquema y el esquema location de aop nuestro tag del archivo de configuración de contexto de Spring:

El aop:pointcut define con una expresión de aspectJ (execution) que el comportamiento transaccional sea ejecutado, para este caso, en todas las operaciones con un valor de retorno void y que reciban cualquier numero/tipo de argumentos, de nuestras clases que terminen en Service y se encuentren en el paquete x.y.service.

Con un aop:advisor simplemente relacionamos el pointcut con el advice previamente definido.


<aop:config>
<aop:pointcut id="operacionesDeServicios" expression="execution(* x.y.service.*Service.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="operacionesDeServicios"/>
</aop:config>


Nota1:
La sintaxis para el comando AspectJ execution es como sigue. Puedes usar ' * ' para indicar "todos", o bien '..' (dos puntos seguidos) para indicar "este paquete o uno más interno", o bien, "más argumentos" si el caso del método:

execution([valorRetornoDelMetodo] [paquete].[clase].[nombreMetodo]([listaArgumentos]))

Ejemplo: Todos los métodos que empiecen con guardar que devuelvan void y reciban por lo menos un long que pertenezcan a las clases que terminen con Dao y sean del paquete x.y.daos o subpaquetes
execution (void x.y.daos..*Dao.guardar*(long..))

Para entender un poco mas sobre las expresiones de aspectJ ve la referencia de aop-aspectj.

Nota 2:
Para no confundirnos con los esquemas, la definición del tag puede quedar como sigue:

<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- todos los demas beans que vimos-->
</beans>




Referencias:

1 comentario:

Que opinas sobre esta publicación?