AspectJ pointcut on constructor object

2020-02-04 21:41发布

问题:

I need to inject few methods to every initialized object using 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.

Thank you!

回答1:

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:

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:

  • 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.

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.



回答2:

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.

Note - you probably don't want to pick up all object creations.. what are you planning on doing with them!