最后,我们加了两个pointcut一级advice,分别实现在调用Point构造函数之后为created的赋值,以及调用setX(int), set(int)以及setName(string)的时候更新lastUpdated成员变量(这里使用!within(PointAspect)排除掉在aspect脚本里面调用set*的情况):
// pointcut the constructor, and set the value for created after() returning(Point p) : call(Point.new(..)) && !within(PointAspect) { System.out.println(thisJoinPointStaticPart); System.out.println("Set created"); p.created = System.currentTimeMillis(); } // define a pointcut for setX and setY pointcut update(Point p): target(p) && call(void Point.set*(..)); // make the lastUpdated updated every time // setX or setY invoked after(Point p): update(p) && !within(PointAspect) { System.out.println("set updated for Point due to " + thisJoinPointStaticPart); p.setUpdated(); }同样,我们可以新建一个单元测试类来进行测试:
package cc.databus.aspect.intertype; import org.junit.Test; public class TestPointAspect { @Test public void test() { Point point = new Point(1,1); point.setName("test"); point.setX(12); point.setY(123); System.out.println(point); } }运行测试,我们能看到如下结果:
call(cc.databus.aspect.intertype.Point(int, int)) Set created set updated for Point due to call(void cc.databus.aspect.intertype.Point.setName(String)) set updated for Point due to call(void cc.databus.aspect.intertype.Point.setX(int)) set updated for Point due to call(void cc.databus.aspect.intertype.Point.setY(int)) Point: {name=test, x=12; y=123, created=1536153649547, updated=1536153649548}可以看到,通过aspect注入的成员对象和成员方法都是工作的。
总结ITD着实是一个强大的功能,能够方便给现有类注入新的功能。但是,笔者认为使用这种方法相对容易出错,尤其在大项目的情况下,如果通过大量的aspect脚本来实现功能,相信对后期的维护是一个很大的挑战。所以,我建议在没有spring这种框架做支撑的情况下,不要大量的使用这种方法为项目造血。
ReferenceAdvanced AspectJ Part II : Inter-type declaration
Inter-type declarations
文章同步发布在我的个人博客https://jianyuan.me上,欢迎拍砖。
传送门: AspectJ中的类型间声明(成员注入)