Java 我们可以在加载类之后重新转换它们吗?

Java 我们可以在加载类之后重新转换它们吗?,java,instrumentation,javaagents,Java,Instrumentation,Javaagents,我们目前使用premain在加载所有类之前转换它们。 但是我们希望控制转换,这意味着我们可以删除/重新添加在方法中插入的代码 所以我们找到了重传,但我不太明白 我们可以重新转换加载的类吗 如果可以,重传类的实例会运行重传代码吗 如果无法完成,是否有任何技术可以在运行时更改某些指定方法的代码 已更新 例如,我们有类A。类A有两个方法foo()和bar(): 我们称之为Instrument.RetransformClass(A.class)。并将bar()更改为: 如果有一个线程已经在调用foo(

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

所以我们找到了重传,但我不太明白

  • 我们可以重新转换加载的类吗
  • 如果可以,重传类的实例会运行重传代码吗
  • 如果无法完成,是否有任何技术可以在运行时更改某些指定方法的代码

  • 已更新

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