我们可以在加载后重新转换 类 吗?
Can we retransform classes after them being loaded?
我们目前使用 premain 在加载之前转换所有 classes。
但是我们想要控制转换,这意味着我们可以 remove/re-add 我们在方法中插入的代码。
所以我们找到了retransform,但是我不太明白。
- 我们可以重新转换 class 加载的内容吗?
- 如果可以的话,重新转换的实例classes 运行会是重新转换的代码吗?
- 如果做不到,有没有什么技术可以在运行的时候把某个指定方法的代码改一下。
已更新
例如,我们有 class A。Class 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
...
如果没有,有什么办法可以实现吗?
因此,在将 class' 字节码加载并安装到 JVM 之前,您已经有一个 ClassFileTransformer
来转换它。现在您会想要沿着 JVM 生命周期再次重新转换,不是吗?
嗯,可以通过 Instrumentation,通过 Instrumentation.retransformClasses method. But first, you have to ensure that retransformation is supported by calling Instrumentation.isRetransformClassesSupported.
进行重新转换
这次改造什么时候生效?根据 javadocs:
If a retransformed method has active stack frames, those active frames continue to run the bytecodes of the original method. The retransformed method will be used on new invokes.
这意味着,在您的示例中,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.
}
触发重新转换时,当前栈帧为:
- 我的重新转换
- 栏
- foo
有一个包含 bar
的活动调用堆栈帧,所以当 myRetransform
returns 它仍然会在 [=57= 中打印一个 "a" ].
然后,bar
将 return 并像这样离开当前堆栈帧:
- foo
而现在是最后触发的转换生效的时间。即:在对 bar
.
的下一次调用中
我们目前使用 premain 在加载之前转换所有 classes。 但是我们想要控制转换,这意味着我们可以 remove/re-add 我们在方法中插入的代码。
所以我们找到了retransform,但是我不太明白。
- 我们可以重新转换 class 加载的内容吗?
- 如果可以的话,重新转换的实例classes 运行会是重新转换的代码吗?
- 如果做不到,有没有什么技术可以在运行的时候把某个指定方法的代码改一下。
已更新
例如,我们有 class A。Class 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
...
如果没有,有什么办法可以实现吗?
因此,在将 class' 字节码加载并安装到 JVM 之前,您已经有一个 ClassFileTransformer
来转换它。现在您会想要沿着 JVM 生命周期再次重新转换,不是吗?
嗯,可以通过 Instrumentation,通过 Instrumentation.retransformClasses method. But first, you have to ensure that retransformation is supported by calling Instrumentation.isRetransformClassesSupported.
进行重新转换这次改造什么时候生效?根据 javadocs:
If a retransformed method has active stack frames, those active frames continue to run the bytecodes of the original method. The retransformed method will be used on new invokes.
这意味着,在您的示例中,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.
}
触发重新转换时,当前栈帧为:
- 我的重新转换
- 栏
- foo
有一个包含 bar
的活动调用堆栈帧,所以当 myRetransform
returns 它仍然会在 [=57= 中打印一个 "a" ].
然后,bar
将 return 并像这样离开当前堆栈帧:
- foo
而现在是最后触发的转换生效的时间。即:在对 bar
.