Java 我们可以在加载类之后重新转换它们吗?
我们目前使用premain在加载所有类之前转换它们。 但是我们希望控制转换,这意味着我们可以删除/重新添加在方法中插入的代码 所以我们找到了重传,但我不太明白Java 我们可以在加载类之后重新转换它们吗?,java,instrumentation,javaagents,Java,Instrumentation,Javaagents,我们目前使用premain在加载所有类之前转换它们。 但是我们希望控制转换,这意味着我们可以删除/重新添加在方法中插入的代码 所以我们找到了重传,但我不太明白 我们可以重新转换加载的类吗 如果可以,重传类的实例会运行重传代码吗 如果无法完成,是否有任何技术可以在运行时更改某些指定方法的代码 已更新 例如,我们有类A。类A有两个方法foo()和bar(): 我们称之为Instrument.RetransformClass(A.class)。并将bar()更改为: 如果有一个线程已经在调用foo(
已更新 例如,我们有类A。类A有两个方法foo()和bar(): 我们称之为Instrument.RetransformClass(A.class)。并将bar()更改为: 如果有一个线程已经在调用foo(),我们是否可以得到输出:
...
a
a
a
b
b
b
...
如果没有,有什么方法可以实现它吗?因此您已经有了一个
ClassFileTransformer
,可以在类的字节码加载并安装到JVM之前对其进行转换。现在,您希望在JVM生命周期中再次进行转换,不是吗
嗯,可以通过仪器,通过这种方法来完成重传。但首先,您必须确保通过调用支持重新传输
这种重译什么时候生效?根据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.
}
触发重传时,当前堆栈帧为:
- myRetransform
- 酒吧
- 福
条
,因此当myRetransform
返回时,它仍会在system.out中打印一个“a”
然后,bar
将返回并离开当前堆栈帧,如下所示:
- 福
现在是最后一次触发的转换生效的时候了。例如:在下一次调用
bar
时,您所说的“transform”是什么意思?我们目前实现的ClassFileTransformer的可能副本,用于在每个类的方法上插入一些代码,这些方法上有一个特殊的注释。据我所知,转换正在改变类的字节码(至少,根据ClassFileTransformer的javadoc#transform()),它看起来像是在改变字节码。您是否尝试过插装。重新转换类()
@这意味着我们可以在agentmain中添加转换器并调用Instrumentation.redefineClasses()来完成这项工作?但是我们怎样才能得到类定义呢?在ClassFileTransformers中调用redefineClasses()?
...
a
a
a
b
b
b
...
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.
}