使用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 =(