Aspectj:lambda表达式的切入点
我有一个正在迁移到Java8的Java6项目。 我们使用aspectj来记录一些用户操作,如按钮点击。
所以有这样的听众:
button.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent clickEvent) {
doSth();
}
});
和poincut:
@Pointcut("execution(public void Button.ClickListener.buttonClick(Button.ClickEvent))")
public void buttonClick() {};
但是由于我们将使用Java8,监听器将如下所示:
button.addClickListener(clickEvent -> doSth());
有什么方法可以编写aspectj切入点,以便它处理新的侦听器?
我想问题是lambda表达式实际上并没有实现/覆盖具有相应名称的任何接口方法,但创建了一个匿名方法。 看看这个例子:
虚拟按钮类,复制我们需要的Vaadin部分:
package de.scrum_master.app;
public class Button {
private ClickListener listener;
public void addClickListener(ClickListener listener) {
this.listener = listener;
}
public void click() {
System.out.println("Clicking button");
listener.buttonClick(new ClickEvent());
}
public static class ClickEvent {}
public static interface ClickListener {
public void buttonClick(ClickEvent clickEvent);
}
}
司机申请:
package de.scrum_master.app;
public class Application {
protected static void doSomething() {}
public static void main(String[] args) {
Button button = new Button();
button.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent clickEvent) {
doSomething();
}
});
button.click();
button = new Button();
button.addClickListener(clickEvent -> doSomething());
button.click();
}
}
如您所见,创建了两个按钮实例,其中一个具有经典的匿名类侦听器,另一个具有lambda侦听器。 两个按钮都会被点击,所以控制台日志看起来像这样:
Clicking button
Clicking button
方面:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class ButtonClickLogger {
@Before("execution(public void *..Button.ClickListener.buttonClick(*..Button.ClickEvent))")
public void logButtonClick(JoinPoint thisJoinPoint) {
System.out.println("Caught button click: " + thisJoinPoint);
}
@Before("within(*..Application)")
public void logAllInListener(JoinPoint thisJoinPoint) {
System.out.println(" " + thisJoinPoint);
}
@Before("execution(void *..lambda*(*..Button.ClickEvent))")
public void logButtonClickLambda(JoinPoint thisJoinPoint) {
System.out.println("Caught button click (lambda): " + thisJoinPoint);
}
}
第一条建议使用类似于你的切入点。 它只能拦截经典的监听器声明。
第二个建议是用于调试目的,并记录驱动程序应用程序中的所有连接点,以显示这里发生了什么。
最后但并非最不重要的一点是,第三条建议显示了一个拦截基于lambda的侦听器的解决方法,依赖于从调试输出获取的lambdas的Java编译器命名知识。 这不是很好,但目前它的工作。 请注意buttonClick(..)
的lambda版本不公开,所以它只是void *..lambda*
,不是public void *..lambda*
。
使用AspectJ控制台输出:
staticinitialization(de.scrum_master.app.Application.<clinit>)
execution(void de.scrum_master.app.Application.main(String[]))
call(de.scrum_master.app.Button())
call(de.scrum_master.app.Application.1())
staticinitialization(de.scrum_master.app.Application.1.<clinit>)
preinitialization(de.scrum_master.app.Application.1())
initialization(de.scrum_master.app.Application.1())
initialization(de.scrum_master.app.Button.ClickListener())
execution(de.scrum_master.app.Application.1())
call(void de.scrum_master.app.Button.addClickListener(Button.ClickListener))
call(void de.scrum_master.app.Button.click())
Clicking button
Caught button click: execution(void de.scrum_master.app.Application.1.buttonClick(Button.ClickEvent))
execution(void de.scrum_master.app.Application.1.buttonClick(Button.ClickEvent))
call(void de.scrum_master.app.Application.doSomething())
execution(void de.scrum_master.app.Application.doSomething())
call(de.scrum_master.app.Button())
call(void de.scrum_master.app.Button.addClickListener(Button.ClickListener))
call(void de.scrum_master.app.Button.click())
Clicking button
execution(void de.scrum_master.app.Application.lambda$0(Button.ClickEvent))
Caught button click (lambda): execution(void de.scrum_master.app.Application.lambda$0(Button.ClickEvent))
call(void de.scrum_master.app.Application.doSomething())
execution(void de.scrum_master.app.Application.doSomething())
更新: AspectJ现在有一个相应的Bugzilla问题。 我刚刚创建了它。 它还指出了最近关于邮件列表的讨论。
链接地址: http://www.djcxy.com/p/27011.html上一篇: Aspectj: Pointcut on lambda expression
下一篇: Kick off mocha tests in Visual Studio Team Services Build