Spring AOP: @AfterThrowing execution pointcut never matches

aspectjspring-aop

I'm completely new to AOP. I need advice to write the correct pointcut. I have a service package that contains all service classes. All the classes implement the Service interface. This interface has a method save(entity). My advice should be executed every time the service.save(entity) method throws a DataIntegrityViolationException.

Here the aspect:

@Component
@Aspect
public class DIVExceptionHandler {
    @AfterThrowing(pointcut = "execution(* myPackage.service.Service.save(*))", throwing = "ex")
        public void handleException(JoinPoint joinPoint, DataIntegrityViolationException ex) {
        //snipped
    }
}

I have both aspectj jars in the CP as explained in Spring AOP documentation and I have added <aop:aspectj-autoproxy/> to Spring configuration and I'm using component scanning. In the log of the test I can see that the aspect is detected as aspetcj aspect:

DEBUG o.s.a.a.a.ReflectiveAspectJAdvisorFactory - Found AspectJ method...

So I believe this is not a configuartion issue and my pointcut expression is wrong. I also tried

@AfterThrowing(pointcut = "execution(* myPackage.service.*.save(*))", throwing = "ex")

But that did also not work.

So what is the correct pointcut expression?

Best Answer

it in fact was a configuration issue.

@AfterThrowing(pointcut = "execution(* myPackage.service.Service.save(*))", throwing = "ex")

Works fine.

The actual problem was that DataIntegrityViolationException is only thrown after the proxy for @Transactional completes the transaction. In my case this happened after my advice can be called.

The solution is to add an order attribute to transaction configuration:

<tx:annotation-driven transaction-manager="transactionManager" order="2000"/>

And then add an @Order annotation to your aspect that is smaller than the one for the transaction:

@Component
@Order(1500) // must be less than order of <tx:annotation-driven />
@Aspect
public class DIVExceptionHandler {
    @AfterThrowing(pointcut = "execution(* myPackage.service.Service.save(*))", throwing = "ex")
        public void handleException(JoinPoint joinPoint, DataIntegrityViolationException ex) {
        //snipped
    }
}

See:

Spring AOP ordering - Transactions before Advise

Related Topic