【问题标题】:Failed to redefine class When I try to retransform class当我尝试重新转换类时无法重新定义类
【发布时间】:2013-09-04 03:40:50
【问题描述】:

我试图动态修改类,例如在一行之前调用 sleep()。我在运行时使用 Attach 方法将代理附加到 jvm。然后我从jvm得到目标类,并修改它(添加一行调用sleep())。我得到了 redine 类错误。我正在使用JDK1.6。我正在使用 ASM 核心 API 来修改类。 错误:

Caused by: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
    at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
    at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:124)

ASM 代码有问题吗?实际上我的 ASM 代码完成了它的工作(添加一行来调用sleep())。当前的 jvm 不支持重新转换类吗?似乎无法执行retransformClasses()retransformClasses() 是否不支持 ASM 操作(在调用 sleep() 的方法中添加一行)?有任何想法吗?谢谢

编辑: 我要修改的类:

import java.util.concurrent.TimeUnit;

public class Person {
    public String name = "abc";
    public String address = "xxxxx" ;

    public void setName(String name) {
    this.name = name;
    }

    public String getName() {
    return name;
    }

    public void sayHello() throws InterruptedException {  
    System.out.println("aaaaaaaaaa");
            System.out.println("Hello World!");
            TimeUnit.SECONDS.sleep(120);
            System.out.println("dd");
        }  
    public void sayHello2() {
            System.out.println("aaaaaaaaaa1");
                System.out.println("Hello World!2");  
        }  

    public static void main (String args[]) {
        try {
            Person p = new Person();
            p.sayHello(); // linenumber #9. A line to call Sleep() should be added before #here.

            p.sayHello2();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }   
}

我的 ASM 代码:

public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) {

    Label la=new Label();
    mv.visitLabel(la);
    int linenumber=la.getOffset();
    if(linenumber==9) {
        mv.visitFieldInsn(Opcodes.GETSTATIC, "java/util/concurrent/TimeUnit", "SECONDS", "Ljava/util/concurrent/TimeUnit;");
        mv.visitLdcInsn(new Long("5"));
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/concurrent/TimeUnit", "sleep", "(J)V");

        super.visitMethodInsn(arg0, arg1, arg2, arg3);

    }
}

【问题讨论】:

    标签: java jvm aop cglib jvmti


    【解决方案1】:

    尚未查看您的代码,我想我可以提出一些建议。当一个类第一次被加载时,除了存储类的字节码,JVM还有一个表格,用来记录每个类中的字段类型和方法的签名。

    您看到的错误表明该类已加载,此签名信息已存储,然后您尝试添加该方法。

    如果您将代理 jar 放到命令行中,则可以在第一次加载类之前执行操作。如果您在存储签名信息之前添加您的方法,您应该会很好。

    如果您必须在进程启动后连接代理,您可能能够转换类,但您可能只能在不更改字段集、它们的类型、方法或它们的集合的情况下进行转换签名。换句话说,您可以更改字节码,但您不必使之前存储的元信息无效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-15
      • 2019-06-08
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      • 2019-07-28
      • 2021-10-10
      相关资源
      最近更新 更多