如何对Java方法进行仪器化?

6

我希望编写一个简单的Java代理程序,可以打印Java程序中被检测到的方法名称。

例如,我要检测的Java程序是:

public class TestInstr {

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

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

}

我想展示类似于这样的内容:
method sayHello has been called
Hello !
method sayHello has been called
Hello !
method sayHello has been called
Hello !

感谢你的帮助!

https://dev59.com/aWPVa4cB1Zd3GeqP8sKF - o_nix
5个回答

11

您可以使用类似Javassist的插装库来完成这个任务。

让我给您举一个单方法的例子,您可以使用Javassist或反射扩展到所有方法上:

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();

查看此链接以获取详细信息:http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/tutorial/tutorial2.html#intro


4

我似乎记得AspectJ可以做类似的事情;然而,我没有经验,探索可能性就得靠你了! :D


我没有使用过它,但从我听到的内容来看,我同意它可能会有用,可以看一下AspectJ。 - SJuan76
1
如果您想要完全控制,可以使用cglib或javassist。但请考虑使用Spring和“around-advice”。 - Xeon

1
在这个方法中,你可以添加。
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();
}
}

您可以使用此方法获取当前方法。
public String getCurrentMethodName() {
 StackTraceElement stackTraceElements[] =
         (new Throwable()).getStackTrace();
 return stackTraceElements[1].toString();
}

我不确定这是否是您正在寻找的内容。


1

我认为这并不容易。

我能想到的唯一选择是实现一个类加载器,并用你创建的存根替换原始类(Hibernate / JPA 为延迟加载执行了类似的操作)。这些存根将执行您需要的操作,然后调用原始类来执行工作。这意味着会有很大的负担(反射调用并不便宜)。


0
如果您只需要记录方法是否被调用,那么面向切面编程(AOP)正是您所需的,无论是AspectJ(静态)还是Spring AOP(动态),两者都提供了强大的功能来实现这一点。 但是,如果您想要进行更多的仪器操作,例如跟踪执行时间、调用跟踪等,则可能需要一些仪器库。 希望对您有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接