java - 我们可以在类加载后重新转换类吗?

标签 java instrumentation javaagents

我们目前使用 premain 在加载所有类之前对其进行转换。 但我们希望控制转换,这意味着我们可以删除/重新添加在方法中插入的代码。

所以我们找到了重新转换,但我不太理解它。

  1. 我们可以重新转换加载的类吗?
  2. 如果可以做到,重新转换的类的实例是否会运行重新转换的代码?
  3. 如果做不到,是否有任何技术可以在运行时更改某些指定方法的代码。
<小时/>

已更新

例如,我们有类 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
...

如果没有,有什么办法可以实现吗?

最佳答案

因此,您已经有了一个 ClassFileTransformer 来在类的字节码加载并安装到 JVM 之前对其进行转换。现在您希望沿着 JVM 生命周期再次重新转换,不是吗?

嗯,重新转换可以通过Instrumentation来完成,通过Instrumentation.retransformClasses方法。但首先,您必须通过调用Instrumentation.isRetransformClassesSupported来确保支持重新转换。 .

这次改造什么时候生效?根据javadoc:

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.
}

当触发重新转换时,当前栈帧为:

  • myRetransform
  • 酒吧

有一个 Activity 的调用堆栈帧,其中包含 bar,因此当 myRetransform 返回时,它仍会在 system.out 中打印“a”。

然后,bar 将返回并离开当前堆栈帧,如下所示:

现在是最后一次触发的转换生效的时间。即:在下一次调用 bar 时。

关于java - 我们可以在类加载后重新转换类吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39140148/

相关文章:

Java 应用程序未关闭连接

java - 如何修改tableview上单个单元格的属性

javascript - 在 Node 版本 > 10 中,await 不会调用 Promise.then 方法

java - 如何在 Jade 中通过 http 向主容器中的代理发送消息?

java - 如何模拟返回最终类的静态方法?

java - 你猜为什么这段代码会打印无限量的 "What' ?”

database - 检测数据库访问

java - 如何在opentelemetry中排除url(健康检查痕迹)

java - 如何管理javaagent的依赖关系?