yeg*_*256 7 java aop constructor aspectj
这就是我正在做的事情:
@Aspect
public class MethodLogger {
@Around("(execution(* *(..)) || initialization(*.new(..))) && @annotation(Foo)")
public Object wrap(ProceedingJoinPoint point) throws Throwable {
// works fine, but only for methods
}
}
Run Code Online (Sandbox Code Playgroud)
该代码段工作正常,但仅适用于方法调用.这是AspectJ maven插件在应用方面后所说的(不是在编译期间,它工作得很好):
around on initialization not supported (compiler limitation)
Run Code Online (Sandbox Code Playgroud)
任何解决方法?我在使用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)
Run Code Online (Sandbox Code Playgroud)
由于技术限制,不存在around()建议initialization()或preinitialization()切入点之类的东西。另外,在进入和退出相应连接点的时间顺序上还存在另一个问题。看这个例子:
public abstract class ApplicationBase {
private int id = 0;
public ApplicationBase(int id) {
this.id = id;
}
}
Run Code Online (Sandbox Code Playgroud)
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");
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
您将看到以下输出:
>> 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
Run Code Online (Sandbox Code Playgroud)
您能看到派生类的预初始化如何在其基类的预初始化之前开始和完成吗?初始化如何以相反的方式工作,但作为额外的复杂性,构造函数执行嵌入在初始化中?
也许现在您明白,即使可以通过 测量初始化around(),也不会反映构造函数的整体执行时间。因此,如果您足够幸运能够拦截构造函数call(),而不是execution()因为您可以访问调用代码,那么您就很好,甚至可以around()像我在示例中所做的那样使用(顺便说一句,这不是线程安全的,但是我试图保持简单)。如果您无法影响调用者,但只能编织被调用者,则需要使用其他技巧,例如方面内部簿记,通过 进入某个构造函数的预初始化,然后通过 退出before()同一构造函数调用的初始化after()。也就是说,您需要在建议执行之间保留一些内部状态。这是可能的,但有点复杂。如果您想进一步讨论这个问题,请告诉我。