构造函数对象上的 AspectJ 切入点 [英] AspectJ pointcut on constructor object

查看:46
本文介绍了构造函数对象上的 AspectJ 切入点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用 AspectJ 向每个初始化的对象注入一些方法.

I need to inject few methods to every initialized object using AspectJ.

我想用这个:

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

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

到对象的切入点初始化,因此我可以将这些方法直接注入作为其他所有对象一部分的对象.

to pointcut initialization of object, so I can inject these methods directly into the object that is part of every other object.

然而,它不起作用.你知道为什么吗?或者有什么其他方法可以 100% 确保每个初始化的对象都将被切入点?*.new 不适用于字符串、列表和其他内容.

However, it does't work. Do you have any idea why? Or what may be an other way how to make 100% sure that every single initialized object will be pointcut? *.new does not work for stuff such String, Lists and others.

谢谢!

推荐答案

用户 selig 是对的:您可能不想拦截所有 对象创建,尤其是 JDK/JRE 类中的那些.但就其价值而言,以下是对什么有效、如何有效、什么无效的解释:

User selig is right: You probably do not want to intercept all object creations, especially not those in JDK/JRE classes. But for what it is worth, here is an explanation of what works and how and what not:

一个小驱动程序应用:

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 中有不同类型的编织:

There are different types of weaving in AspectJ:

  • 编译时编织 (CTW):只能编织由 ajc(AspectJ 编译器)编译的类.这不包括 JDK/JRE 类以及您未从源代码编译的第 3 方库.上面的示例输出显示了编译时编织的效果.
  • 二进制编织 (BW):AspectJ 编译器用于将方面代码直接编译为现有的字节码.这适用于您自己的预编译应用程序类以及第 3 方库.理论上,如果您将 rt.jar 放在 AspectJ 编译器的路径中,它也适用于 JDK/JRE 类.JDK/JRE 编织有点棘手,但我以前做过.您可以生成一个新的 rt.jar 编织版本,或者只是一个带有一些编织 JDK 类的小 JAR 文件,然后在启动应用程序时将其添加到 JDK/JRE 的引导类路径中.
  • 加载时编织 (LTW):基本上这是 BW,但在类加载期间动态完成.在这个 AspectJ 场景中,您只能在方面编织器的影响下编织由类加载器加载的类.因此,它适用于您自己的代码和第 3 方库,但通常不适用于在加载方面编织器之前加载的 JDK/JRE 引导类.这是一个鸡蛋和鸡蛋类型的问题:weaver 需要运行 JRE,然后才能加载它,但为了编织 JRE 类,weaver 必须在这些类被引导之前就在那里.
  • Compile-time weaving (CTW): Only classes which are compiled by ajc (AspectJ compiler) can be woven. This excludes JDK/JRE classes and also 3rd party libraries which you do not compile from source. the sample output from above shows the effect of compile-time weaving.
  • Binary weaving (BW): The AspectJ compiler is used to compile aspect code directly into existing byte code. This works with your own precompiled application classes as well as with 3rd party libraries. Theoretically it also works with JDK/JRE classes if you put rt.jar on the AspectJ compiler's in-path. JDK/JRE weaving is a bit tricky, but I have done it before. You can produce a newly woven version of rt.jar or just a small JAR file with a few woven JDK classes which then you prepend to the boot-classpath of the JDK/JRE when firing up your application.
  • Load-time weaving (LTW): Basically this is BW, but done dynamically during class-loading. In this AspectJ scenario you can only weave classes which are loaded by a classloader under the influence of an aspect weaver. Thus, it works with you own code and 3rd party libraries, but usually not with JDK/JRE bootstrapping classes which are loaded before the aspect weaver is loaded. It is a hen-and-egg type of problem: The weaver needs the JRE to be running before it can be loaded, but in order to weave JRE classes the weaver would have to be there before those classes are bootstrapped.

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

Now what you can easily do is intercept calls to JDK/JRE constructors from your own code oder woven 3rd party code, as you can see in the log output line saying call(java.lang.String()). You cannot intercept internal calls from JRE class to JRE class though.

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

Having said all that I really wonder what kind of horrible thing you want to do. I mean, you explain it and it sounds like a tremendous design error. Or you want to re-invent the wheel and write some kind of profiler or debugger which already exists. What do you expect from intercepting each single object creation? It would tremendously slow down your application, drastically increase memory consumption and create even more objects, if only the strings you are logging. Please reconsider and try to think about what you really want to do. Maybe then we can suggest a smart way of achieving your goal.

这篇关于构造函数对象上的 AspectJ 切入点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆