如何横切带注释的方法和构造函数? [英] How to crosscut annotated methods and constructors?

查看:30
本文介绍了如何横切带注释的方法和构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这就是我正在做的:

@Aspect
public class MethodLogger {
  @Around("(execution(* *(..)) || initialization(*.new(..))) && @annotation(Foo)")
  public Object wrap(ProceedingJoinPoint point) throws Throwable {
    // works fine, but only for methods
  }
}

该代码段工作正常,但仅适用于方法调用.这就是 AspectJ maven 插件 在应用方面后所说的(不是在编译期间,效果很好):

The snippet works fine, but only for method calls. This is what AspectJ maven plugin is saying after applying the aspect (not during its compilation, which works just fine):

around on initialization not supported (compiler limitation)

有什么解决方法吗?我使用的是 OpenJDK 7:

Any workaround? I'm with OpenJDK 7:

java version "1.7.0_05"
Java(TM) SE Runtime Environment (build 1.7.0_05-b06)
Java HotSpot(TM) 64-Bit Server VM (build 23.1-b03, mixed mode)

推荐答案

由于技术限制,在 initialization()preinitialization() 切入点.并且在进入和退出相应连接点的时间顺序中还有另一个问题.看这个例子:

Due to technical limitations there is no such thing as around() advice on initialization() or preinitialization() pointcuts. And there is another problem in the chronological order of when the corresponding joinpoints are being entered and exited. Look at this example:

public abstract class ApplicationBase {
    private int id = 0;

    public ApplicationBase(int id) {
        this.id = id;
    }
}

public class Application extends ApplicationBase {
    private String name = "<unnamed>";

    public Application(int id, String name) {
        super(id);
        this.name = name;
    }

    public static void main(String[] args) {
        new Application(1, "Foo");
        new Application(2, "Bar");
    }
}

public aspect ExecutionTimingAspect {
    private String indentText = "";

    pointcut constructorCall() :
        call(*Application*.new(..));

    pointcut constructorRelated() :
        constructorCall() ||
        initialization(*Application*.new(..)) ||
        preinitialization(*Application*.new(..)) ||
        execution(*Application*.new(..));

    after() : constructorRelated() {
        indentText = indentText.substring(2);
        System.out.println(indentText + "<< " + thisJoinPointStaticPart);
    }

    before() : constructorRelated() {
        System.out.println(indentText + ">> " + thisJoinPointStaticPart);
        indentText += "  ";
    }

    Object around() : constructorCall() {
        long startTime = System.nanoTime();
        Object result = proceed();
        System.out.println(indentText + "Constructor runtime = " + (System.nanoTime() - startTime) / 1.0e9 + " s\n");
        return result;
    }
}

您将看到以下输出:

>> call(Application(int, String))
  >> preinitialization(Application(int, String))
  << preinitialization(Application(int, String))
  >> preinitialization(ApplicationBase(int))
  << preinitialization(ApplicationBase(int))
  >> initialization(ApplicationBase(int))
    >> execution(ApplicationBase(int))
    << execution(ApplicationBase(int))
  << initialization(ApplicationBase(int))
  >> initialization(Application(int, String))
    >> execution(Application(int, String))
    << execution(Application(int, String))
  << initialization(Application(int, String))
<< call(Application(int, String))
Constructor runtime = 0.00123172 s

>> call(Application(int, String))
  >> preinitialization(Application(int, String))
  << preinitialization(Application(int, String))
  >> preinitialization(ApplicationBase(int))
  << preinitialization(ApplicationBase(int))
  >> initialization(ApplicationBase(int))
    >> execution(ApplicationBase(int))
    << execution(ApplicationBase(int))
  << initialization(ApplicationBase(int))
  >> initialization(Application(int, String))
    >> execution(Application(int, String))
    << execution(Application(int, String))
  << initialization(Application(int, String))
<< call(Application(int, String))
Constructor runtime = 0.00103393 s

你能看到派生类的预初始化在其基类预初始化之前是如何开始和完成的吗?以及初始化是如何工作的,但作为一个额外的复杂构造函数执行嵌入在初始化中?

Can you see how preinitialisation of the derived class starts and finishes before preinitialisation of its base class? And how initialisation works just the other way around, but as an additional complication constructor execution is embedded in initialisation?

也许现在您明白了,即使可以通过 around() 测量初始化,也不能反映构造函数的整体执行时间.因此,如果您足够幸运能够拦截构造函数 call() 而不是 execution() 因为您可以访问调用代码,那么您就可以了,甚至可以使用around() 正如我在示例中所做的那样(顺便说一下,它不是线程安全的,但我尽量保持简单).如果你不能影响调用者,而只能编织被调用者,则需要使用其他技巧,例如通过 before() 进入某个构造函数的预初始化时的方面内部簿记,然后当相同构造函数调用的初始化通过 after() 退出.IE.您需要在建议执行之间保持一些内部状态.这是可能的,但稍微复杂一些.如果你想进一步讨论这个问题,请告诉我.

Maybe now you understand that just measuring initialisation, even if it was possible via around(), would not reflect the constructor's overall execution time. So if you are lucky enough to be able to intercept constructor call() instead of execution() because you have access to the calling code, you are fine and can even use around() as I did in my example (which is, by the way, not thread-safe, but I tried to keep it simple). If you cannot influence the caller, but can only weave the callee, you need to use other tricks, such as aspect-internal bookkeeping of when preinitialisation of a certain constructor is entered via before() and then when initialisation of the same constructor call is exited via after(). I.e. you need to keep some internal state in between advice executions. This is possible, but a little more complicated. If you want to discuss this further, please let me know.

这篇关于如何横切带注释的方法和构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆