如何在使用AspectJ的cflow()时删除java..*调用?

3

我在下面的示例代码中描述了我的问题。 HelloWorld 类是我的源代码,需要由 HelloWorldTracer 切面进行检测。我的目标是查找所有位于 HelloWorld.main() 控制流程中的方法调用。但我不关心与 java.lang.* 包中任何类型相关的方法调用(例如:java.lang.StringBuilder)。

package com.abc;

public class HelloWorld {

    public static void main(String args[]) {
        StringBuilder str = new StringBuilder();
        str.toString();
        Sample.testMethod();
    }
}

package com.abc;

public class Sample {

    public static void testMethod()
    {
        StringBuilder str = new StringBuilder();
        str.toString(); 
    }

}


public aspect HelloWorldTracer {

    pointcut helloWorldTracker() : 
        execution(* com.sybase.HelloWorld.main(..)) && within(com.abc..*) &&  !within(HelloWorldTracer);

    pointcut methodTracker():
         cflow(helloWorldTracker()) 
         && !within(java.lang..*) && !within(HelloWorldTracer);

    Object around(): methodTracker()
    {

        System.out.println("Inside advice..." + thisJoinPointStaticPart.getSignature().toString() );
        Object o = proceed();
        return o;
    }

}

使用上述切点时,尽管在methodTracker()切入点中明确指定了!within(java.lang..*),但仍会建议使用StringBuilder类型。我还尝试过!within(java.lang.StringBuilder)!execution(String java.langStringBuilder.toString(..)) ,但都没有成功。欢迎任何帮助我限制从java.lang..*获取建议的类型。


你尝试过使用 !within(java.lang...(..)) 吗? - SirVaulterScoff
我知道这个问题很旧了,但仍然被列为未回答。如果我的回答看起来合适的话,你能否接受并点赞一下?谢谢。 - kriegaex
2个回答

1
"Nitzan Volman的建议不是你想要的。首先,在您的代码示例中,您可能希望更改:"
"

首先,在您的代码示例中,您可能希望更改

"
execution(* com.sybase.HelloWorld.main(..))

execution(* com.abc.HelloWorld.main(..))

解决了这个问题后,你会收到很多警告,因为你试图使用 around() 建议 initialization()preinitialization() 切入点,但由于编译器的限制,这是不可能的。

然后当你将输出行更改为

System.out.println(thisJoinPointStaticPart);

你将看到代码中真正发生的事情:

execution(void com.abc.HelloWorld.main(String[]))
call(java.lang.StringBuilder())
call(String java.lang.StringBuilder.toString())
call(void com.abc.Sample.testMethod())
staticinitialization(com.abc.Sample.<clinit>)
execution(void com.abc.Sample.testMethod())
call(java.lang.StringBuilder())
call(String java.lang.StringBuilder.toString())

即,您不仅拦截方法调用(或者您是想捕获方法执行,这并不相同?),而且还拦截所有(很多)类型的连接点。请尝试以下内容:
public aspect HelloWorldTracer {
    pointcut belowHelloWorldMain() :
        cflow(execution(* com.abc.HelloWorld.main(..)));

    pointcut methodTracker():
        belowHelloWorldMain() &&
        call(* *(..)) &&
        !call(* java.lang..*(..)) &&
        !within(HelloWorldTracer);

    Object around(): methodTracker() {
        System.out.println(thisJoinPointStaticPart);
        return proceed();
    }
}

结果:

call(void com.abc.Sample.testMethod())

如果你只想截取自己(编织的)类的执行而不是调用,那么这更简单,因为此时你不需要排除Java类:

public aspect HelloWorldTracer {
    pointcut belowHelloWorldMain() :
        cflow(execution(* com.abc.HelloWorld.main(..)));

    pointcut methodTracker():
        belowHelloWorldMain() &&
        execution(* *(..));

    Object around(): methodTracker() {
        System.out.println(thisJoinPointStaticPart);
        return proceed();
    }
}

结果:

execution(void com.abc.HelloWorld.main(String[]))
execution(void com.abc.Sample.testMethod())

如您所见,现在甚至包括了 main(..)

-1

我认为在这种情况下,你应该使用execution而不是within

pointcut methodTracker():
     cflow(helloWorldTracker()) 
     && !execution(* java.lang..*(..)) && !within(HelloWorldTracer);

methodTracker() 捕获所有不在 java.lang. 中调用的方法。

Sample.testMethod() 调用 StringBuilder.toString(),因此由切入点返回。


这是不正确的。它仍然会产生之前的相同问题。此外,!execution(* java.lang..*(..))除非您正在尝试编织JDK类,否则没有任何意义,因为否则JDK方法执行将永远不会被拦截。;-) - kriegaex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接