参数类型是基于实际调用方法,还是基于add()
签名?
在 AspectJ 中,call()
您需要为切入点指定方法或构造函数签名。在这种情况下,该add()
方法没有任何由 注释的参数@Entity
,因此您尝试执行的操作不起作用。这是使用反射的解决方法:
示例注释:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Entity {}
样本实体:
package de.scrum_master.app;
@Entity
public class MyEntity {}
驱动应用:
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
public class Application {
List<Object> myList = new ArrayList<>();
public static void main(String[] args) {
Application application = new Application();
application.myList.add("foo");
application.myList.add(new MyEntity());
application.myList.add("bar");
application.myList.add(new MyEntity());
}
}
方面:
package de.scrum_master.aspect;
import de.scrum_master.app.Application;
import de.scrum_master.app.Entity;
public aspect EntityAddInterceptor {
pointcut addEntity(Object addedObject) :
within(Application) && call(* *.add(*)) && args(addedObject);
before(Object addedObject) : addEntity(addedObject) {
if (addedObject.getClass().isAnnotationPresent(Entity.class))
System.out.println(thisJoinPointStaticPart + " -> " + addedObject);
}
}
输出:
call(boolean java.util.List.add(Object)) -> de.scrum_master.app.MyEntity@19dc6592
call(boolean java.util.List.add(Object)) -> de.scrum_master.app.MyEntity@54906181
至于控制流匹配变体,我认为从命名的角度来看,假设getMyList()
不添加任何内容而只返回一个列表是有意义的。可能你宁愿做类似的事情application.getMyList().add("foo")
,在这种情况下,add()
它实际上是在控制流之外(之后),getMyList()
因为它对其结果进行操作。
如果 OTOH 您有一个addToList(Object element)
真正调用的假设方法,add()
您可以使用cflow()
. 让我们修改代码示例:
修改驱动应用程序:
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
public class Application {
List<Object> myList = new ArrayList<>();
public void addToMyList(Object element) { reallyAddToMyList(element); }
private void reallyAddToMyList(Object element) { myList.add(element); }
public static void main(String[] args) {
Application application = new Application();
application.myList.add("foo");
application.myList.add(new MyEntity());
application.addToMyList("bar");
application.addToMyList(new MyEntity());
}
}
修改方面:
package de.scrum_master.aspect;
import de.scrum_master.app.Entity;
public aspect EntityAddInterceptor {
pointcut addEntity(Object addedObject) :
cflow(execution(* *.addToMyList(*))) && (call(* *.add(*)) && args(addedObject));
before(Object addedObject) : addEntity(addedObject) {
if (addedObject.getClass().isAnnotationPresent(Entity.class))
System.out.println(thisJoinPointStaticPart + " -> " + addedObject);
}
}
新输出:
call(boolean java.util.List.add(Object)) -> de.scrum_master.app.MyEntity@323ba00
如您所见,只记录了一个呼叫。它是来自的reallyAddToMyList()
,不是来自的main()
。
更新 2014-07-21 - 更好的方面修改:
这个更优雅的解决方案归功于 Andy Clement(AspectJ 维护者),他在AspectJ 邮件列表中提到了它。它从上面显示了我的两个变体,但使用&& @args(Entity)
而不是if (addedObject.getClass().isAnnotationPresent(Entity.class))
:
package de.scrum_master.aspect;
import de.scrum_master.app.Application;
import de.scrum_master.app.Entity;
public aspect EntityAddInterceptor {
pointcut addEntity(Object addedObject) :
within(Application) && call(* *.add(*)) && args(addedObject) && @args(Entity);
before(Object addedObject) : addEntity(addedObject) {
System.out.println(thisJoinPointStaticPart + " -> " + addedObject);
}
pointcut addEntitySpecial(Object addedObject) :
cflow(execution(* *.addToMyList(*))) && (call(* *.add(*)) && args(addedObject)) && @args(Entity);
before(Object addedObject) : addEntitySpecial(addedObject) {
System.out.println(thisJoinPointStaticPart + " -> " + addedObject + " [special]");
}
}
两种变体都处于活动状态的输出如下所示:
call(boolean java.util.List.add(Object)) -> de.scrum_master.app.MyEntity@229ff6d1
call(boolean java.util.List.add(Object)) -> de.scrum_master.app.MyEntity@1976bf9e
call(boolean java.util.List.add(Object)) -> de.scrum_master.app.MyEntity@1976bf9e [special]