AspectJ - 是否可以捕获建议的执行?

时间:2011-05-18 10:00:51

标签: aspectj tracing pointcuts

我有CachingAspect使用around建议对正确注释的方法执行一些简单的缓存。现在,我想要做的是跟踪缓存和特别是around建议。

到目前为止,我能够拦截around建议中的方法调用,而不是建议本身。最终,我希望获得around建议所建议的方法的签名。有可能吗?

提前致谢!

3 个答案:

答案 0 :(得分:1)

答案 1 :(得分:1)

您可以在建议中使用thisJoinPoint.getSignature()来获取方法签名,如下所示:

pointcut tolog1() : execution(* Activity+.*(..)) ;
before() : tolog1() {
    String method = thisJoinPoint.getSignature().toShortString();

    Log.d(ATAG, "=========== entering " + method+", parms="+Arrays.toString(thisJoinPoint.getArgs()));
}

答案 2 :(得分:1)

你是什么意思

  

[adviceexecution切入点]对我不起作用

对我来说它的效果很好,就像这样:

public aspect MetaAspect {
    before() : within(DummyAspect) && adviceexecution() {
        System.out.println("MetaAspect: " + thisJoinPointStaticPart.getSignature());
        for (Object arg : thisJoinPoint.getArgs())
            System.out.println("    " + arg);
    }
}

从那时起,看一下打印的签名,你应该能够进一步改进从DummyAspect中选择的建议,如果有多个,并且它们有不同的签名。


<强>更新

好的,您已编辑了您的问题,并说明您需要确定的不仅仅是adviceexecution(),还包括截获的方法的签名。没有100%的解决方案,但是如果您确保截获的建议以某种方式引用thisJoinPointStaticPart的方法,JoinPoint.StaticPart的实例将被添加到建议自己的签名中,并且可以从您的签名中访问元方面。这是一个完整的代码示例:

驱动程序应用程序:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        Application application = new Application();
        application.writeProperty("fullName", "John Doe");
        application.readProperty("firstName");
        application.doSomething(11);
    }

    public void writeProperty(String name, String value) {}
    public String readProperty(String name) { return "foo"; }
    public void doSomething(int number) {}
}

缓存方面:

package de.scrum_master.aspect;

public aspect CachingAspect {
    pointcut readMethods(String propertyName) :
        execution(* *.read*(String)) && args(propertyName);

    before(String propertyName) : readMethods(propertyName) {
        System.out.println(
            "[CachingAspect] Read method called for property '" + propertyName + "'"
        );
    }

    Object around(String propertyName) : readMethods(propertyName) {
        System.out.println(
            "[CachingAspect] Caching property '" + propertyName +
            "' in method " + thisJoinPointStaticPart.getSignature()
        );
        return proceed(propertyName);
    }
}

如您所见,这方面有两点建议。第一个不访问任何连接点成员,第二个成员。即我们将只能在元方面找到第二个目标签名。

元方面:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint.StaticPart;

public aspect AdviceInterceptor {
    before() : within(CachingAspect) && adviceexecution() {
        System.out.println("[AdviceInterceptor] Intercepting " + thisJoinPointStaticPart);
        boolean foundSignature = false;
        for (Object arg : thisJoinPoint.getArgs()) {
            if (arg instanceof StaticPart) {
                foundSignature = true;
                StaticPart jpStaticPart = (StaticPart) arg;
                System.out.println("[AdviceInterceptor] Target method = " + jpStaticPart.getSignature());
                break;
            }
        }
        if (!foundSignature)
            System.out.println("[AdviceInterceptor] Target method cannot be determined from advice signature");
    }
}

元建议迭代其参数以便找到JoinPoint.StaticPart类型参数。如果找到一个,它会打印出目标签名,否则会在循环后打印失败记录。

示例输出:

[AdviceInterceptor] Intercepting adviceexecution(void de.scrum_master.aspect.CachingAspect.before(String))
[AdviceInterceptor] Target method cannot be determined from advice signature
[CachingAspect] Read method called for property 'firstName'
[AdviceInterceptor] Intercepting adviceexecution(Object de.scrum_master.aspect.CachingAspect.around(String, AroundClosure, JoinPoint.StaticPart))
[AdviceInterceptor] Target method = String de.scrum_master.app.Application.readProperty(String)
[CachingAspect] Caching property 'firstName' in method String de.scrum_master.app.Application.readProperty(String)