【问题标题】:execution Vs. call Join point执行与。呼叫加入点
【发布时间】:2013-08-10 13:36:40
【问题描述】:

我有两个不同的方面类来计算执行测试程序的非静态方法调用的数量。第一个方面计算“调用”连接点上的方法:

pointcut methodCalls() : call (!static * test..*(..));
before(): methodCalls() {
        counter.methodCallCounter();
}

而第二个方面计算“执行”连接点上的方法:

pointcut methodCalls() : execution (!static * test..*(..));
before(): methodCalls() {
        counter.methodCallCounter();
}

methodCallCounter() 是计数器类中的静态方法。

小测试程序的方法调用次数是一样的。但是,当我用更大的程序更改测试程序时,第二个方面类(带有执行切入点)中的方法调用次数多于带有调用切入点的方面类中的方法调用次数。这是合理的,因为呼叫加入点不会挑选出使用 super 进行的呼叫,因此不会计算它们。

但是,我遇到了一个情况,对于程序的具体执行,带有“调用切入点”的切面类中的非静态方法调用的数量高于带有“执行切入点”的切面类中的方法调用的数量。我找不到任何解释为什么会发生这种情况。对第二种情况的原因的任何想法表示赞赏。

【问题讨论】:

  • 不确定...我建议打印出一些有关差异的信息。也许打印出“thisJoinPoint”对象。
  • call() 和 execute() 有很多不同之处,请阅读这篇博文:perfspy.blogspot.com/2013/09/…

标签: aop aspectj


【解决方案1】:

其实如果你理解call()execution()切入点的基本区别,解释就很简单了:前者拦截所有调用者(即方法调用的来源),后者拦截调用本身,无论它们在哪里起源于。

那么两个切入点触发的拦截次数怎么会不同呢?

  • 如果您从自己的代码中调用 JRE/JDK 方法,AspectJ 可以编织到您的调用中,但不能编织到 JDK 内的执行连接点中(除非您已创建编织 J​​DK 作为准备步骤)。因此,调用次数将高于执行次数。
  • 同样,如果您调用第三方库中的方法,而这些方法由于在 LTW 或 CTW 期间不在路径中而未使用 AspectJ 编织,则不会再次捕获执行。
  • 最后但并非最不重要的一点是,如果您自己的编织代码被第三方库或 JRE/JDK 类调用,则可能会发生相反的情况。在这种情况下,计算的执行次数将高于调用次数,因为它们源自您的 AspectJ 代码无法控制的地方。

通常,在所有情况下,原因都是整体使用代码与编织代码子集之间的差异。换句话说:您(或方面)控制范围内和之外的代码之间的差异。

【讨论】:

  • 我们可以说call()是在编译时中确定的,而execution()是在运行时中确定的吗?
  • 不,我们不能。 cflow()if () 这样的切入点是在运行时确定的。
  • @kriegaex 如何在 call() 和 execution() 之间做出选择?有资源吗?
  • AspectJ manual 解释了基本区别。在this answer 中,我使用伪代码更详细地解释了它,以便更好地理解。基本区别在于call() 将代码编织到调用方法的所有位置,即如果从代码中的 500 个不同位置调用它,它会将您的建议代码编织到这 500 个位置。但是,execute() 被编织到方法本身中,即只有一次,这通常更有效。
  • (续)选择哪一个取决于您是否可以控制被调用的代码并可以在其中编织方面。如果可以,您通常会使用execution(),如果不能,则留下call()。可能还有其他情况可以选择call(),例如如果要绑定this() 或使用JoinPoint.getThis() 以执行调用对象(调用者)而不是被调用对象(被调用者)。但这太复杂了,无法用一两条简短的评论来解释。
【解决方案2】:

hy,这张图片可能会帮助您直观地了解执行和调用之间的区别:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多