2

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

@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()。我怎样才能避免这种情况?

4

2 回答 2

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

        }

    }

}

显然,这只有在所有调用都在同一个线程中完成时才有效。线程局部变量也有一些其他的缺点,很适合阅读它们。

于 2012-09-05T13:21:36.270 回答
0

我只带着我的 iPad 在路上,所以我现在无法测试它,但你可以尝试以下方式:

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

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

对不起 AspectJ 原生语法,我只是更熟悉它。

于 2012-09-05T17:38:47.597 回答