构造函数对象上的AspectJ切入点

时间:2013-06-27 08:55:24

标签: java aop aspectj code-injection pointcut

我需要使用AspectJ为每个初始化对象注入几个方法。

我想用这个:

pointcut vistaInjection(Object o)
    : initialization(java.lang.Object.new() ) 
    && target(o)
    && !within(objectAspect);

before(Object o): methodInjection(o){System.err.println("INIT");}

切入对象的初始化,因此我可以将这些方法直接注入到作为每个其他对象一部分的对象中。

然而,它不起作用。你知道为什么吗?或者可能是另一种方式如何100%确定每个初始化对象都是切入点? * .new不适用于字符串,列表和其他内容。

谢谢!

2 个答案:

答案 0 :(得分:17)

用户selig是对的:您可能不希望拦截所有对象创建,尤其不是JDK / JRE类中的那些。但是对于它的价值,这里有一个解释什么有效,怎么有,有没有:

一个小小的驱动程序应用程序:

public class Application {
    public static void main(String[] args) {
        new Application();
        new String();
    }
}

具有不同类型的构造函数相关切入点/建议的方面:

public aspect ObjectCreationAspect {
    before() : preinitialization(*.new(..)) && !within(ObjectCreationAspect) {
        System.out.println(thisJoinPointStaticPart);
    }

    before() : initialization(*.new(..)) && !within(ObjectCreationAspect) {
        System.out.println(thisJoinPointStaticPart);
    }

    before() : call(*.new(..)) && !within(ObjectCreationAspect) {
        System.out.println(thisJoinPointStaticPart);
    }

    before() : execution(*.new(..)) && !within(ObjectCreationAspect) {
        System.out.println(thisJoinPointStaticPart);
    }
}

编织驱动程序应用程序的输出:

call(Application())
preinitialization(Application())
initialization(Application())
execution(Application())
call(java.lang.String())

<强>解释

AspectJ中有不同类型的编织:

  • 编译时编织(CTW):只能编织由 ajc (AspectJ编译器)编译的类。这不包括JDK / JRE类以及您不从源代码编译的第三方库。上面的示例输出显示了编译时编织的效果。
  • 二进制编织(BW):AspectJ编译器用于将方面代码直接编译为现有字节代码。这适用于您自己的预编译应用程序类以及第三方库。理论上,如果将 rt.jar 放在AspectJ编译器的路径中,它也适用于JDK / JRE类。 JDK / JRE编织有点棘手,但我之前已经完成了。您可以生成 rt.jar 的新编织版本,或者只是一个带有一些编织JDK类的小JAR文件,然后在启动应用程序时将其添加到JDK / JRE的引导类路径中。
  • 加载时间编织(LTW):基本上这是BW,但在类加载期间动态完成。在这个AspectJ场景中,您只能在一个方面编织器的影响下编织由类加载器加载的类。因此,它适用于您自己的代码和第三方库,但通常不使用在加载方面编织器之前加载的JDK / JRE引导类。这是一个鸡蛋和蛋类型的问题:编织者需要JRE在可以加载之前运行,但是为了编织JRE类,编织器必须在那些类被引导之前存在。

现在您可以轻松地从您自己的代码或编织的第三方代码拦截调用到JDK / JRE构造函数,正如您在日志输出行中看到的call(java.lang.String())所示。但是,您无法拦截从JRE类到JRE类的内部调用。

说了这么多,我真的很想知道你想做什么样的可怕事情。我的意思是,你解释它,这听起来像一个巨大的设计错误。或者你想重新发明轮子并编写一些已经存在的探查器或调试器。你期望拦截每个单个对象创建什么?它会极大地降低应用程序的速度,大大增加内存消耗并创建更多对象(如果只记录您正在记录的字符串)。请重新考虑并尝试考虑你真正想做的事情。也许那时我们可以建议一种实现目标的聪明方法。

答案 1 :(得分:0)

你试过吗

pointcut vistaInjection(Object o)
    : (initialization(*.new()) || (initialization(*.new(..)))
    && target(o)
    && !within(objectAspect);

即。在任何事情上调用.new()并允许没有和一些参数。

注意 - 你可能不想选择所有对象创作..你打算用它们做什么!