面向切面编程中无限递归的自动检测
1 引言
在当前主流的面向切面编程语言(如 AspectJ)中,一个常见的问题是面向切面程序很容易包含导致意外无限递归的代码。这种意外的无限递归通常是由于通知(advice)调用其他通知或调用它们所调用的方法引起的。尽管程序员可能会有意在面向切面程序中使用递归来解决递归问题,但在实践中,大部分递归是无意的,属于编程错误。
为避免无限递归,程序员通常采用一种特定的解决方法,即对于每个切面 A,将其切入点(pointcut)与 !cflow(within(A))
切入点进行连接。这种方法可以防止切面自我调用导致的无限递归,但由于 cflow
切入点无法静态匹配,会带来相当大的运行时开销。而且,即使运行时开销不是问题,这种方法也要求程序员遵循特定的约定,将每个切入点与 !cflow(within(A))
进行连接。
测试是发现所有编程范式中错误的常用方法,包括面向切面程序中的无限递归。然而,大多数情况下,测试之后还需要进一步分析才能找出故障的原因。
Bodden 等人提出了 AspectJ 语言的扩展 AspectJ ,通过对切面进行分层,防止切面调用更高层或同一层的切面,从而完全避免了切面中的无限递归。但这种解决方案限制了程序员只能使用 AspectJ 进行编程。为解决这一限制,他们提供了将 AspectJ 程序重构为 AspectJ* 程序的方法,但对于大型程序来说,重构现有程序可能会很繁琐。
还有一种不同的方法是在 XFindBugs 中实现的,它通过检查特定 AspectJ 编译器生成的字节码来