java 构造函数对象上的 AspectJ 切入点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17338788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AspectJ pointcut on constructor object
提问by Marosh
I need to inject few methods to every initialized object using AspectJ.
我需要使用 AspectJ 向每个初始化的对象注入一些方法。
I thought using this :
我想用这个:
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.
到对象的切入点初始化,因此我可以将这些方法直接注入作为每个其他对象一部分的对象。
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.
但是,它不起作用。你知道为什么吗?或者有什么其他方法可以 100% 确定每个初始化的对象都将被切入点?*.new 不适用于字符串、列表和其他内容。
Thank you!
谢谢!
回答by kriegaex
User selig is right: You probably do not want to intercept allobject 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:
用户 selig 是对的:您可能不想拦截所有对象创建,尤其是 JDK/JRE 类中的对象。但对于它的价值,这里是对什么有效、如何和什么无效的解释:
A little driver application:
一个小驱动程序应用:
public class Application {
public static void main(String[] args) {
new Application();
new String();
}
}
An aspect with different types of constructor-related pointcuts/advice:
具有不同类型的构造函数相关切入点/建议的方面:
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);
}
}
The woven driver application's output:
编织驱动程序应用程序的输出:
call(Application())
preinitialization(Application())
initialization(Application())
execution(Application())
call(java.lang.String())
Explanation:
解释:
There are different types of weaving in AspectJ:
AspectJ 中有不同类型的编织:
- 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.jaron 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.jaror 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.
- 编译时织入(CTW):只能织入由ajc(AspectJ 编译器)编译的类。这不包括 JDK/JRE 类以及您未从源代码编译的第 3 方库。上面的示例输出显示了编译时编织的效果。
- Binary Weaving (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 必须在这些类被引导之前就在那里。
Now what you can easily do is intercept callsto 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.
现在您可以轻松地做的是从您自己的代码或编织的 3rd 方代码中拦截对 JDK/JRE 构造函数的调用,正如您在日志输出行中看到的那样call(java.lang.String())
。但是,您无法拦截从 JRE 类到 JRE 类的内部调用。
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.
说了这么多,我真的很想知道你想做什么样的可怕的事情。我的意思是,你解释一下,这听起来像是一个巨大的设计错误。或者您想重新发明轮子并编写某种已经存在的分析器或调试器。你对拦截每个对象的创建有什么期望?它会极大地减慢您的应用程序的速度,显着增加内存消耗并创建更多的对象,如果只是您正在记录的字符串。请重新考虑并尝试考虑您真正想做的事情。也许那时我们可以提出一种实现目标的明智方法。
回答by selig
Have you tried
你有没有尝试过
pointcut vistaInjection(Object o)
: (initialization(*.new()) || (initialization(*.new(..)))
&& target(o)
&& !within(objectAspect);
i.e. calling .new()
on anything and allowing no and some arguments.
即呼吁.new()
任何事情,并允许没有和一些参数。
Note - you probably don't want to pick up allobject creations.. what are you planning on doing with them!
注意 - 你可能不想拿起所有的对象创建......你打算用它们做什么!