Search code examples
springtransactionsaopaspectj

@Transactional on aspect advice possible?


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();
    }
}

Solution

  • 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!