Can I apply the @Transactional tag to an aspect advice? I'm trying to wrap all calls to the service layer (com.mycompany.app.myapp.service.*) in a transaction using aspects. My aspect is properly intercepting the calls to the service layer, but I can't figure out how to start a transaction. I thought I could apply the @Transactional tag and because I've got the tag, it'd pick it up and begin the transaction. What am I missing?
XML configuration:
<bean id="systemArchitectureAspect" class="com.mycompany.app.myapp.aspect.SystemArchitecture"/>
<bean id="transactionAspect" class="com.mycompany.app.myapp.aspect.MyAspect"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction"
class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="10" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
Aspect w/pointcuts:
package com.mycompany.app.myapp.aspect;
@Aspect
public class SystemArchitecture {
@Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
public void inServiceLayer() {};
@Pointcut( "execution(* com.mycompany.data..*.*(..))" )
public void inDataAccessLayer() {};
}
The advice I'm trying to apply to my pointcuts:
package com.mycompany.app.myapp.aspect;
@Aspect
public class TransactionAspect {
@Transactional
@Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
{
return pjp.proceed();
}
}
Below I have an example that shows how you can use @Transactional
together with your inServiceLayer()
Pointcut
. I have chosen to separate the normal flow from the exception flow. That is why I do not use the @Around
advice.
@Aspect
public class TransactionAspect {
private TransactionService transactionService = new TransactionServiceNull();
@Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
public void inServiceLayer() {};
@Pointcut("execution(@org.springframework.transaction.annotation
.Transactional * *(..))")
public void transactionalMethod() {}
@Before("transactionalMethod() && inServiceLayer()")
public void beforeTransactionalMethod(JoinPoint joinPoint) {
transactionService.beginTransaction();
}
@AfterReturning("transactionalMethod() && inServiceLayer()")
public void afterTransactionalMethod(JoinPoint joinPoint) {
transactionService.commit();
}
@AfterThrowing(pointcut = "transactionalMethod() && inServiceLayer()",
throwing = "e")
public void afterThrowingFromTransactionalMethod(JoinPoint joinPoint,
RuntimeException e) {
transactionService.rollback();
}
public void setTransactionService(
final TransactionService transactionService) {
this.transactionService = transactionService;
}
}
After a quick look on your code I have to ask why you have annotated your Pointcut
with @Transactional
? You should only mark your business methods that you want to be executed in a transaction with that.
I hope this helps!