如何交叉注释方法和构造函数? [英] How to crosscut annotated methods and constructors?

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

问题描述

这是我在做什么:

  @Aspect 
public class MethodLogger {
@ $($)
public Object wrap(ProceedingJoinPoint point)throws Throwable()($($) {
//工作正常,但仅适用于方法
}
}

代码段工作正常,但仅适用于方法调用。这是 AspectJ maven插件在应用该方面(不是在其编译期间,

 不支持初始化(编译器限制)

任何解决方法?我使用OpenJDK 7:

  java版本1.7.0_05
Java(TM)SE运行环境build 1.7.0_05-b06)
Java HotSpot(TM)64位服务器虚拟机(构建23.1-b03,混合模式)

$ b由于技术限制,没有这样的事情 around()建议在 initialization() preinitialization()切入点。并且在相应的连接点被输入和退出时的时间顺序中存在另一个问题。看看这个例子:

  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()||
初始化(* Application * .new(..))||
preinitialization(* Application * .new(..))||
执行(* Application * .new(..));

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

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

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

您将看到以下输出:

 >> call(Application(int,String))
>>预初始化(Application(int,String))
< preinitialization(Application(int,String))
>> preinitialization(ApplicationBase(int))
<<预初始化(ApplicationBase(int))
>>初始化(ApplicationBase(int))
>>执行(ApplicationBase(int))
<<执行(ApplicationBase(int))
<<初始化(ApplicationBase(int))
>>初始化(Application(int,String))
>>执行(Application(int,String))
<<执行(Application(int,String))
<<初始化(Application(int,String))
<< call(Application(int,String))
构造函数runtime = 0.00123172 s

>> call(Application(int,String))
>>预初始化(Application(int,String))
< preinitialization(Application(int,String))
>> preinitialization(ApplicationBase(int))
<<预初始化(ApplicationBase(int))
>>初始化(ApplicationBase(int))
>>执行(ApplicationBase(int))
<<执行(ApplicationBase(int))
<<初始化(ApplicationBase(int))
>>初始化(Application(int,String))
>>执行(Application(int,String))
<<执行(Application(int,String))
<初始化(Application(int,String))
<< call(Application(int,String))
构造函数runtime = 0.00103393 s

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



也许现在你明白,只是测量初始化,即使它是可能通过 around(),不会反映构造函数的总体执行时间。因此,如果你有幸能够拦截构造函数 call()而不是 execution()到调用代码,你是罚款,甚至可以使用 around(),因为我在我的例子(这是,顺便说一下,不是线程安全,但我试过保持简单)。如果你不能影响调用者,但只能编织被调用者,你需要使用其他的技巧,例如在预先初始化某个构造函数时通过 before(),然后通过 after()退出相同构造函数调用的初始化。也就是说你需要在建议执行之间保持一些内部状态。这是可能的,但有点复杂。如果您想进一步讨论这个问题,请告诉我们。


This is what I'm doing:

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

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)

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)

解决方案

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;
    }
}

You will see the following output:

>> 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?

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天全站免登陆