我们目前使用premain在加载之前转换所有类。 但我们希望控制变换,这意味着我们可以删除/重新添加我们在方法中插入的代码。
所以我们发现了转换,但我不太明白。
已更新
例如,我们有A类.A类有两个方法foo()和bar():
void foo() {
while(true) {
bar();
}
}
void bar() {
System.out.println("a");
}
我们称之为Instrument.retransformClasses(A.class)。并将bar()更改为:
void bar() {
System.out.println("b");
}
如果有一个线程已经调用了foo(),我们可以得到输出:
...
a
a
a
b
b
b
...
如果没有,有没有办法实现它?
答案 0 :(得分:1)
所以你已经有一个ClassFileTransformer
来改变一个班级'字节码在加载并安装到JVM之前。现在你想要在JVM生命周期中再次重新转换,不是吗?
嗯,转换可以通过Instrumentation,通过Instrumentation.retransformClasses方法完成。但首先,您必须通过调用Instrumentation.isRetransformClassesSupported来确保支持重新转换。
这次重新转换何时生效?根据javadocs:
如果重新传输的方法具有活动堆栈帧,那些活动帧将继续运行原始方法的字节码。重新传输的方法将用于新的调用。
这意味着,在您的示例中,foo()
会反复调用bar()
。如果同时重新转换bar
,则转换后的代码将生效调用bar
的下一次迭代。
我将为您的示例添加更多复杂性:
void foo() {
while(true) {
bar();
}
}
void bar() {
myRetransform();
System.out.println("a");
}
void myRetransform() {
// This is where a retransformation of class A, method bar, is triggered.
}
当触发重新转换时,当前堆栈帧为:
有一个带有bar
的有效调用堆栈框架,因此当myRetransform
返回时,它仍然会打印一个" a"在system.out。
然后,bar
将返回并保留当前的堆栈帧:
现在是最后一次触发转换生效的时间。即:在下次调用bar
时。