Reputation: 54005
Let's say I have an aspect wrapper on all public methods of my services which detaches entities from database before returning them to controller:
@Around("execution(public * *(..)) && @within(org.springframework.stereotype.Service)")
When one service is calling another directly, this wrapper is being triggered as well. For instance:
@Service
class ServiceA {
@Autowired
ServiceB b;
public void foo() {
b.bar();
}
}
@Service
class ServiceB {
public void bar() {
}
}
When I call ServiceA.foo()
, the wrapper is triggering around the nested call to bar()
as well.
It should trigger around the call to foo()
, but not bar()
. How can I avoid this?
Upvotes: 2
Views: 421
Reputation: 67297
I am on the road with my iPad only, so I cannot test it now, but you could try something along the lines of:
pointcut myCalls() :
execution(public * *(..)) && @within(org.springframework.stereotype.Service);
pointcut myCallsNonRecursive() :
myCalls() && !cflowbelow(myCalls())
around() : myCallsNonRecursive() {
// ...
}
Sorry for the AspectJ native syntax, I am just more familiar with it.
Upvotes: 0
Reputation: 20297
I've sometimes resolved this kind of problems using ThreadLocal variables. Try something like:
@Aspect
public class DetacherAspect {
private final ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();
@Around("execution(public * *(..)) && @within(org.springframework.stereotype.Service)")
public Object execute(ProceedingJoinPoint pjp) throws Throwable {
boolean isNested = threadLocal.get() != null;
if (!isNested) {
// Set some object (better create your own class) if this is the first service
threadLocal.set(new Object());
}
try {
... // Your aspect
} finally {
// Clean thread local variables
if (!isNested) {
threadLocal.remove();
}
}
}
}
Obviously, this will only work when all calls are done in the same thread. Thread local variables have some other drawbacks too and is good to read about them.
Upvotes: 1