lunes, octubre 11, 2004

Transacciones con AOP en Spring

AOP (Aspect Oriented Programming) nos ofrece una forma diferente de declarar servicios para muestra aplicación y sin entrar en detalle en todo el mundo AOP, podemos utilizar solamente un subconjunto de su funcionalidad para agregar transaccionalidad declarativa a los servicios que desarrollemos, utilizando method interception.

Spring AOP integra el soporte AOP en la infraestructura misma de Spring, permitiéndonos declarar la transaccionalidad de los servicios en el mismo XML de configuración de nuestros beans.

Típicamente, en Spring 1.1.1, definimos una plantilla para nuestras transacciones:

<bean id="daoTxProxyTemplate" abstract="true" 

class=
"org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
en la cual está especificado el transactionManager que utilizaremos, y una serie de patterns de nombres de métodos, sobre los cuales definiremos que tipo de transacción es requerida para los métodos que se ajusten a ese pattern.

Luego solo queda comenzar a definir nuestros servicios, con la implementación como inner bean:

<bean id="itemManager" parent="daoTxProxyTemplate">

<property name="target">
<bean class="com.example.services.itemManagerImpl">
<property name="itemManagerDAO"><ref bean="itemManagerDAO"/></property>
</bean>
</property>
</bean>
Asi, ante cada llamada al método saveItem de la clase itemManagerImpl (definida en el bean itemManager), Spring creará una transacción (o reutilizará una existente) antes de la llamada, y hará el commit luego de ella.

Mas adelante podríamos seguir definiendo nuestro servicios, por ejemplo uno sin propiedades, y con los parámetros de propagación sobreescritos:

<bean id="miServicio" parent="daoTxProxyTemplate">

<property name="target">
<bean class="com.example.services.otroServicio"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
En cuanto a los tipos de propagación para las transacciones y su nivel de aislamiento, lo mas utilizado es simplemente PROPAGATION_REQUIRED, pero podemos optar por todos los definidos en la interfaz TransactionDefinition, utilizando el formato "PROPAGATION_NAME, ISOLATION_NAME, readOnly, timeout_NNNN, +Exception1, -Exception2", siendo PROPAGATION_NAME el único requerido.

En la definición de la plantilla de transacciones, también definimos una propiedad transactionManager. Este bean, puede tomar la forma de

<bean id="transactionManager" 

class=
"org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref bean="defaultDataSource"/></property>
</bean>
si trabajamos con JDBC directamente, o

<bean id="transactionManager" 

class=
"org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
si utilizamos Hibernate.

Queda para otro post como definir el sessionFactory de Hibernate y el dataSource (con pooling o sin el) necesarios.

1 comentario:

amf_sp dijo...

Hola lo que no veo es con esto de las transacciones delarativas no hace falta hacer el rollback en el código java?.


Es decir solo se configura con esta declaración