Cichy
Cichy

Reputation: 1329

Check in Spring AOP if method is called by another annotated method

I use in my Spring boot project aspect that is fired on every public method in annotated class:

@Aspect
@Component
public class DeletedAwareAspect {
    @Before("@within(com.example.DeleteAware)")
    public void aroundExecution(JoinPoint pjp) throws Throwable {
        //... some logic before
    }

    @After("@within(com.example.DeleteAware)")
    public void cleanUp(JoinPoint pjp) throws Throwable {
       //... some logic after
    }
}

Usage of that aspect is below:

@DeleteAware
@Service
public class MyService {
    public void foo() {}
}
@DeleteAware
@Service
public class MyAnotherService {
    @Autowired
    private MyService service;

    public void anotherFoo() {}

    public void VERY_IMPORTANT_METHOD() {
        service.foo();
    }
}

MyService.foo() and MyAnotherService.anotherFoo() works as expected. But here is the problem - if method wrapped by aspect is called by another aspected method (like VERY_IMPORTANT_METHOD()), I dont want to fire aspect twice, but only once. How to check from Aspect whether method is called inside another aspected method?

Upvotes: 0

Views: 1215

Answers (1)

kriegaex
kriegaex

Reputation: 67297

Like I said, if you would switch to native AspectJ you could use percflow() aspect instantiation and/or cflow() pointcuts, but I will not explain that here in detail because you are looking for a Spring AOP solution. Like R.G said, it is actually quite simple: Use a thread-local counter for the aspect nesting level and only do something (e.g. deleting something in the after advice) if the counter is zero.

@Aspect
@Component
public class DeletedAwareAspect {
  private ThreadLocal<Integer> nestingLevel = ThreadLocal.withInitial(() -> 0);

  @Before("@within(com.example.DeleteAware)")
  public void aroundExecution(JoinPoint pjp) {
    int level = nestingLevel.get() + 1;
    nestingLevel.set(level);
    System.out.println("BEFORE " + pjp + " -> " + level);
  }

  @After("@within(com.example.DeleteAware)")
  public void cleanUp(JoinPoint pjp) {
    int level = nestingLevel.get() - 1;
    nestingLevel.set(level);
    System.out.println("AFTER " + pjp + " -> " + level);
    if (level == 0)
      System.out.println("Deleting something");
  }
}

Upvotes: 1

Related Questions