How to instrument java methods?

2019-01-18 15:32发布

问题:

I want to write a simple java agent which can print the name of a method called by the java program instrumented.

For example, my java program I want to instrument is:

public class TestInstr {

public static void sayHello() {
    System.out.println("Hello !");
}

public static void main(String args[]) {
    sayHello();
    sayHello();
    sayHello();
 }

}

I would like to display something like this :

method sayHello has been called
Hello !
method sayHello has been called
Hello !
method sayHello has been called
Hello !

Thanks for your help!

回答1:

You can use an instrumentation library such as Javassist to do that.

Let me give you an example for a single method, you can extend this to all methods using Javassist or reflection:

ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("TestInstr");
CtMethod m = cc.getDeclaredMethod("sayHello");
m.insertBefore("{ System.out.println(\"method sayHello has been called\"); }");
cc.writeFile();

Check this link for details: http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/tutorial/tutorial2.html#intro



回答2:

I seem to remember that AspectJ can do stuff like this; I have no experience with it, however, so exploring possibilities is up to you! :D



回答3:

In the method you could add

public class TestInstr {

public static void sayHello() {
System.out.println("method sayHello has been called");
System.out.println("Hello !");
}

public static void main(String args[]) {
sayHello();
sayHello();
sayHello();
}
}

You could use this to get the current method

public String getCurrentMethodName() {
 StackTraceElement stackTraceElements[] =
         (new Throwable()).getStackTrace();
 return stackTraceElements[1].toString();
}

I'm not sure if this is what you're looking for.



回答4:

I do not think it is easy.

The only option I can think of would be implementing a class loader and replacing the original classes with stubs created by you (Hibernate / JPA does something like that for lazy loading). The stubs would perform the operation you require and then call the original classes to perform the work. It would mean a heavy burden (reflection calls are not cheap).



回答5:

If your need is simply to record a method was called or not, then aspect-oriented programming is exact what you need, no matter AspectJ(static) or Spring AOP(dynamic), both provide powerful capability to do that. However you may need some instrument libraries in case you want to do more instrument stuff, such like track the execution time, calling track. Hope it helps.