使用java.lang.reflection的构造函数的AspectJ切入点

以下示例是减少真正的问题,因为它尽可能地尝试简化。

我有一个java接口,以及几个实现该接口的对象,如:

public interface Shape{ public void draw(); public void erase(); public boolean isDrawn(); } public class Square implements Shape{ @Override public void draw(){ //TODO: method implementation } @Override public void erase(){ //TODO: method implementation } Override public boolean isDrawn(){ //TODO: method implementation return false; } } public Triangle implements Shape{ //same as above } public Circle implements Shape{ //same as above } 

这是我的程序的结构。 通过使用AspectJ,我想拥有一个包含实现接口的每个对象的映射。 为此,我试图通过使用以下方面捕获构造函数:

 public aspect ShapeHolderAspect{ private Map map = new HashMap(); private int count = 0; pointcut shapeInit(): call((Shape+).new(..)); Object around(): shapeInit() { System.out.println("capturing new"); Shape shapeType = (Shape)proceed(); map.put(++count, shapeType); return shapeType; } } 

如果我使用以下场景创建一个Shape,此代码将起作用:

 public static void main(String[] args){ Shape myShape = new Circle(); } 

但是,我使用的是java语言reflection,所以从技术上讲我不会调用“new”构造函数。 相反,我找到包的路径,并创建传递带有类名称的字符串的对象:

 public static void main(String[] args){ String shapeClassName = args[0]; Class classType = Class.forName("myPackage.figures" + "." + shapeClassName); Shape myShape =(Shape)classType.getConstructor().newInstance(); } 

通过这种方式,AspectJ无法检测到我正在创建形状。 我该如何解决?

新的,更好的版本:

好吧,虽然下面的旧版本实际上捕获了所有构造函数的执行,但是关于构造函数执行的around建议返回null,因为有问题的对象尚未初始化。 所以你最终会在你的方面得到一个空指针的映射。 为了解决这个问题,您需要将this()绑定到变量(示例代码使用默认包名称):

 public class Application { public static void main(String[] args) throws Exception { new Circle().draw(); ((Shape) Class.forName("Triangle").getConstructor().newInstance()).isDrawn(); ((Shape) Class.forName("Square").getConstructor().newInstance()).erase(); } } 
 import java.util.HashMap; import java.util.Map; public aspect ShapeHolderAspect { private Map map = new HashMap(); private int count = 0; after(Shape shape): execution(Shape+.new(..)) && this(shape) { System.out.println(thisJoinPointStaticPart); map.put(++count, shape); } after() : execution(* Application.main(..)) { System.out.println("\nList of shapes:"); for (int key : map.keySet()) System.out.println(" " + key + " -> " + map.get(key)); } } 

输出如下:

 initialization(Circle()) initialization(Triangle()) initialization(Square()) List of shapes: 1 -> Circle@1a2961b 2 -> Triangle@12d03f9 3 -> Square@5ffb18 

顺便说一句,如果你绝对需要一个around建议,因为你想在对象创建之前之后做其他的事情,它看起来像这样:

 void around(Shape shape): execution(Shape+.new(..)) && this(shape) { System.out.println(thisJoinPointStaticPart); proceed(shape); map.put(++count, shape); } 

旧的,不完整的版本:

很简单,只是拦截构造函数execution而不是call

 pointcut shapeInit(): execution(Shape+.new(..)); 

这样你就可以编织成被调用的代码(被调用者),而不是调用代码(调用者)。 因此,呼叫者是否发出reflection或正常呼叫并不重要。

发现以下切入点将完成这项工作:

 pointcut lockReflectInit(): call(public Object java.lang.reflect.Constructor.newInstance(..)); 

然而,这将捕获newInstance的所有调用,而不仅仅是返回Shape =(