【发布时间】:2013-11-27 06:31:01
【问题描述】:
我想追踪,哪个方法调用了 java.lang.Thread.start() 方法。 如何使用 ASM 字节码库实现它...?
【问题讨论】:
-
您可以修补 java.lang.Thread 并使用反射来查找和记录调用者。
标签: bytecode java-bytecode-asm
我想追踪,哪个方法调用了 java.lang.Thread.start() 方法。 如何使用 ASM 字节码库实现它...?
【问题讨论】:
标签: bytecode java-bytecode-asm
您可以编写自己的 javaagent 来转换所有方法。它应该搜索java.lang.Thread.start() 调用并在它们之前添加日志记录。
因此,您应该检查所有方法并查找以下字节码指令:
INVOKEVIRTUAL java/lang/Thread start ()V
并在指令前插入类似这样的内容:
GETSTATIC java/lang/System out Ljava/io/PrintStream;
LDC ${current_method_name_and_desc}
INVOKEVIRTUAL java/lang/PrintStream println (Ljava/lang/String;)V
【讨论】:
start 方法本身,而是所有其他方法,它调用 start。我将扩展我的答案并展示主要思想。
start 不是本地方法,它在内部调用start0,这是本地的。因此,不推荐使用 start 进行检测是可能的。
嗯,这在很大程度上取决于您要跟踪的代码量:
Thread.start:那么您需要检测应用程序的所有类。Thread.start,包括Java 标准API 的那些:然后您需要检测Thread,但是很难实现。为了实现 (1) 目标,您可以注册一个 Java agent (tutorial attached),它解析加载的类的任何方法并检查它们是否调用了 Thread.start。每当您发现这样的方法时,您都需要为这些方法添加某种跟踪机制,例如对System.out.println 的调用。 ASM has an excelent tutorial 他们甚至在关于方法字节码的章节中提供了一个类似的示例。此外,您可以使用ASMifier 来打印出您实际需要实现的代码。
(2)目标更难实现。为了完成这项工作,您必须redefine the class for Thread 这可能会导致一些严重的问题,因为它是一个系统类。在Thread 类中,您可以调用Thread.getStackTrace 并检查由StackTraceElement 表示的当前调用堆栈顶部的方法名称。然后,您必须再次启用跟踪此方法,例如调用 System.out.println。
我会向您推荐第一个策略,因为这更容易实现。此外,您可能会破坏 JDK 的使用许可,具体取决于您运行应用程序的位置。
【讨论】:
new Throwable().getStackTrace()吗?获取调用者并不难(尽管不建议用于生产代码)。
Thread.getStackTrace 比创建Throwable 更容易。