避免嵌套调用

时间:2012-09-05 12:47:16

标签: spring aop aspectj

假设我的服务的所有公共方法都有一个方面包装器,它将实体从数据库中分离出来,然后再将它们返回给控制器:

@Around("execution(public * *(..)) && @within(org.springframework.stereotype.Service)")

当一个服务直接调用另一个服务时,也会触发此包装器。例如:

@Service
class ServiceA {
    @Autowired
    ServiceB b;

    public void foo() {
        b.bar();
    }
}

@Service
class ServiceB {
    public void bar() {
    }
}

当我调用ServiceA.foo()时,包装器也会触发围绕bar()的嵌套调用。

它应该触发foo()的呼叫,而不是bar()。我怎么能避免这个?

2 个答案:

答案 0 :(得分:1)

我有时会使用ThreadLocal变量来解决这类问题。尝试类似:

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

        }

    }

}

显然,这只适用于所有调用都在同一个线程中完成的情况。线程局部变量也有一些其他缺点,并且很好地阅读它们。

答案 1 :(得分:0)

我只使用我的iPad,所以我现在无法测试,但你可以尝试以下方式:

pointcut myCalls() :
    execution(public * *(..)) && @within(org.springframework.stereotype.Service);
pointcut myCallsNonRecursive() :
    myCalls() && !cflowbelow(myCalls())

around() : myCallsNonRecursive() {
    // ...
}

对于AspectJ原生语法很抱歉,我对它更熟悉。