Search code examples
springaspectjspring-aopspring-aspects

How to exclude classes from triggering Aspect method call


I have a method in an @Aspect service method called logChangesAndAnnounceNewContributions that fires whenever somewhere in the webapp the save method of Spring-data's JpaRepository is called. I don't want the logChanges method to be called when the save method is used within the Aspect class itself, so i used this in the pointcut definition !within(Services.SystemListenerService). But its not having any effect! The save method is still being called despite using this condition in the definition. The full definition looks like this:

@AfterReturning("execution(* org.springframework.data.jpa.repository.JpaRepository.save(..))" +
           "&& !within(Services.SystemListenerService) && args(entity)")
    private void logChangesAndAnnounceNewContributions(Object entity){

What am i missing here?

EDIT: I tried changing !within content to !within(@org.aspectj.lang.annotation.Aspect *) but that doesn't work either..


Solution

  • Assuming that Services.SystemListenerService is the fully qualified name of your aspect (class name SystemListenerService, package name Services with strange upper-case first letter), within() does not work because at the time of execution(* org.springframework.data.jpa.repository.JpaRepository.save(..)) we are not within(Services.SystemListenerService) anyway but rather within(org.springframework.data.jpa.repository.JpaRepository). So there is the logical error in your pointcut.

    There are ways to solve this in AspectJ, such as

    • call(A) && !adviceexecution(),
    • execution(A) && !cflow(execution(B)),

    but both pointcut types are unsupported in Spring AOP. So you

    • either need to activate full AspectJ via LTW in Spring
    • or abuse some Spring methods in order to get the real object underneath the proxy via ((Advised) myProxy).getTargetSource().getTarget() and call the method directly on that object from your aspect
    • or obtain a stack trace from a newly created exception or from the current thread and inspect it manually - very ugly.

    Sorry, but Spring AOP is just "AOP lite", I think you should go for AspectJ. The second option is also a bit hacky but will probably work.