2012-09-05 173 views
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()。我怎样才能避免这种情况?

回答

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

     } 

    } 

} 

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

+0

我想出了这个,让我想知道是否真的没有简单的方法。感觉如此普遍和自然。 –

+0

@KonradGarus:好吧,我在使用这个时需要在两个调用之间共享一些对象。但我认为它符合你的问题,并没有那么复杂(但我不喜欢疯狂地使用线程局部变量)。 – sinuhepop

+0

我明白了。我绝对适合,我只是想知道是否没有开箱即用的解决方案。谢谢,如果没有这样的答案,我会接受。 –

0

我只用我的iPad的道路上,所以现在我无法测试它,但你可以尝试沿着线的东西:

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

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

对不起AspectJ的本地语法,我只是比较熟悉用它。

+0

从AspectJ文档看来,它似乎可以工作,但Spring文档很快告诉我它不适用于Spring。 –

+0

我不是Spring用户。它没有办法与AJ编织并使用Spring中的编织类,甚至不能将Spring中的编织委派给AJ? – kriegaex

+0

好的,我只是st upon了这一点,我希望它可以帮助:[使用AspectJ与Spring应用程序](http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html# AOP-使用-AspectJ的) – kriegaex