`

asm----字节码操纵

    博客分类:
  • J2SE
 
阅读更多
想通过asm的代码生成来写.class文件至少得了解下面的东西。
       1.ICONST_x相当于常量,前面的I是指int型,还有其它型的CONST,这个量为比如ICONST_1就是1,对于后面不同的操作,它会再指定实际的类型。使用visitInsn(ICONST_1)就是说定义了一个为1的临时量压到栈里面,但不会定义一个变量。-1<=ICONST<=5;如果要定义大点的数就使用visitVarInsn(BIPUSH, 10)
  2.ISTORE是把栈顶的临时量保存成变量如visitVarInsn(ISTORE, 1)保存在位置1,如果想把变量值拿出来用如下进行,把位置1的值拿出来放到栈顶visitVarInsn(ILOAD, 1);
  3.visitIincInsn(1, 1);对位置是1的变量进行自增,自增幅度为后面参数所定义的1。
  4.对于栈的操作还有DUP,POP,SWAP等命令。需要理解栈的存取。
  5.for循环例子代码,使用了两个label来完成,开始初学对字节码不明白,所以先从.class文件反译成字节码来进行。相当于实现:
-----------------------------
  for(int i = 1; i >= 10;) {
          i++;
          byte byte0 = 2;
       }
-----------------------------
       Label forLabel = new Label();
       Label endLabel = new Label();
       mw.visitInsn(ICONST_1);
       mw.visitVarInsn(ISTORE, 1);
  mw.visitLabel(forLabel);
       mw.visitVarInsn(ILOAD, 1);
       mw.visitVarInsn(BIPUSH, 10);
       mw.visitJumpInsn(IF_ICMPLT, endLabel);
       mw.visitIincInsn(1, 1);// ++操作
       mw.visitInsn(ICONST_2);
       mw.visitVarInsn(ISTORE, 2); //这循环体内进做了 int c = 2的操作
       mw.visitJumpInsn(GOTO, forLabel);
       mw.visitLabel(endLabel);
  5.条件语句例子:没用使用GOTO,相当于实现
       -------------------------
  int i = 3;
       if(i >= 0)
          i = 1 + i;
  --------------------------
       Label label = new Label();
       mw.visitInsn(ICONST_3);
       mw.visitVarInsn(ISTORE, 1);
       mw.visitVarInsn(ILOAD, 1);
       mw.visitJumpInsn(IFLT, label);
       mw.visitInsn(ICONST_1);
       mw.visitIntInsn(ILOAD, 1);
       mw.visitInsn(IADD);
       mw.visitVarInsn(ISTORE, 1);
       mw.visitLabel(label);


--------------------------------------------------

    Visitor访问者模式作用于某个对象的操作,它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作。
  在asm中,ClassReader对象可以接受一个实现ClassVisitor接口的对象来进行对读入的Class的访问与控制。
  其中,如asm文档展示了一个很简单的ClassPrinter类,用来打印类相关信息。
ClassPrinter cp = new ClassPrinter();
ClassReader cr = new ClassReader("java.lang.Runnable");
cr.accept(cp, 0);
ClassPrinter实现了ClassVisitor接口
public class ClassPrinter implements ClassVisitor {
public void visit(int version, int access, String name, String signature,
       String superName, String[] interfaces) {
      System.out.println(name + " extends " + superName + " {");
}

public void visitSource(String source, String debug) {
      System.out.println("[" + source + "]");
}

public void visitOuterClass(String owner, String name, String desc) {
      System.out.println("[outerClass]" + owner + " " + name + " " + desc);
}

public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
      return null;
}

public void visitAttribute(Attribute attr) {
      System.out.println("[Attribute]" + attr);
}

public void visitInnerClass(String name, String outerName,
       String innerName, int access) {
}

public FieldVisitor visitField(int access, String name, String desc,
      String signature, Object value) {
      System.out.println(" " + desc + " " + name);
      return null;
}

public MethodVisitor visitMethod(int access, String name, String desc,
       String signature, String[] exceptions) {
      System.out.println(" " + name + desc);
      return null;
}

public void visitEnd() {
      System.out.println("}");
}
}

  对于ClassVisitor接口,asm在其之上提供了一个适配器的功能。ClassAdapter用来对ClassReader和ClassWriter中间的适配工作。ClassAdapter实现了ClassVisitor接口,是一个具体类。我们可以继承于ClassAdapter类来实现我们的逻辑。
  ClassAdatper作为具体类的好处是我们只需要重写我们关心的东西。使用ClassAdapter我们可以在字节码级别更改我们的类,一个应用就是实现我们的AOP。
这是我们的目标类

package com.c2.asm;
public class B {
public int number = 20;
public int getNumber() {
      System.out.println("class B logic");
      return number;
}

public static void main(String[] args) {
      B b = new B();
      System.out.println(b.getNumber());
}
}

  我们的任务是对getNumber()方法的更改,在打印"class B logic"之前实现使number的值由原来的20增加到23,在打印"class B logic"之后实现打印"after"语句。
       设计类AopExampleAdapter,当中使用到了AopMethodAdapter来实施主要改写逻辑。

class AopMethodAdapter extends MethodAdapter implements Opcodes {
public AopMethodAdapter(MethodVisitor mv) {
      super(mv);
}

// 执行方法之前
@Override
public void visitCode() {
      mv.visitVarInsn(ALOAD, 0); //将第一个参数带入方法,并将其推送至执行堆栈
      mv.visitInsn(DUP);
      mv.visitFieldInsn(GETFIELD, "com/c2/asm/B", "number", "I");
      mv.visitInsn(ICONST_3);
      mv.visitInsn(IADD);
      mv.visitFieldInsn(PUTFIELD, "com/c2/asm/B", "number", "I");

}

//执行方法之后

@Override
public void visitInsn(int opcode) {
if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) {
      mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
        "Ljava/io/PrintStream;");
      mv.visitLdcInsn("after");
      // invokes the 'println' method (defined in the PrintStream class)
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
        "(Ljava/lang/String;)V");
}

      mv.visitInsn(opcode);

}

//修改类中使用到的stack和locals大小,我没仔细算过 +2,+3都瞎写的

@Override

public void visitMaxs(int maxStack, int maxLocals) {
      mv.visitMaxs(maxStack + 2, maxLocals + 3);
}

}

public class AopExampleAdapter extends ClassAdapter implements Opcodes {

public AopExampleAdapter(ClassVisitor cv) {
      super(cv);

}

public MethodVisitor visitMethod(int access, String name, String desc,
       String signature, String[] exceptions) {
      MethodVisitor mv;
      mv = cv.visitMethod(access, name, desc, signature, exceptions);
  // 当匹配到getNumber方法后进行对方法修改
      if (mv != null && name.equals("getNumber")) {
       mv = new AopMethodAdapter(mv);
      }
      return mv;
}

}

  使用AopMethodAdapter如ClassVisitor方法一样,因为AopMethodAdapter是基于ClassVisitor来实现的。



“aload_0”指示符将第一个参数带入方法,并将其推送至执行堆栈。“invokespecial”指示符,不言而喻,它将调用实例的方法,但是忽略传统的动态绑定
分享到:
评论
1 楼 完美天龙 2014-12-08  
      ------------------------- 
  int i = 3; 
       if(i >= 0) 
          i = 1 + i; 
  -------------------------- 
       Label label = new Label(); 
       mw.visitInsn(ICONST_3); 
       mw.visitVarInsn(ISTORE, 1); 
       mw.visitVarInsn(ILOAD, 1); 
       mw.visitJumpInsn(IFLT, label); 
       mw.visitInsn(ICONST_1); 
       mw.visitIntInsn(ILOAD, 1); 
       mw.visitInsn(IADD); 
       mw.visitVarInsn(ISTORE, 1); 
       mw.visitLabel(label); 

  -------------------------- 

请教下、这里如果要把i的最终值输出,语法要怎么写?

相关推荐

    asm-analysis-2.0.jar.zip

    4. 字节码操纵:除了分析,ASM还能对字节码进行修改。通过ASM,开发者可以创建新的类,或者在已有的类上添加、删除或修改方法,甚至是改变字节码的执行流程。 ASM库的使用通常涉及到以下几个步骤: 1. 创建类解析...

    asm-7.1(jar以及源码).rar

    4. **字节码操作(Bytecode Manipulation)**:ASM 提供了一系列API,允许精确地操纵字节码,包括插入、删除、替换和插入新的指令。 5. **元数据(Metadata)**:ASM 允许在生成的类中插入自定义元数据,这在实现...

    asm-debug-all-3.3-sources.jar.zip

    4. **适应性强**:ASM库设计灵活,可以用于各种用途,从简单的类加载到复杂的字节码操纵,适用于很多不同的Java框架和工具。 5. **性能优化**:通过直接操作字节码,ASM可以用来优化代码性能,例如消除无用的计算,...

    asm-analysis-3.0.jar.zip

    - **字节码操纵**:在运行时修改类和方法,例如在插桩技术中,用于插入额外的日志、监控或优化代码。 - **框架实现**:许多Java框架,如Spring,使用ASM来实现底层的元数据处理和动态类生成。 在使用asm-analysis-...

    asm-all-3.3

    1. **灵活性**:ASM提供了直接操纵字节码的能力,使得开发者可以在运行时生成、修改或插入代码,实现高度定制的功能。 2. **高性能**:由于ASM是在字节码级别操作,因此可以实现高效的代码生成和优化,对于性能敏感...

    asm2.2.2 asm-commons-2.2.2 asm-util-2.2.1 cglib-nodep-2.1_3

    ASM库广泛用于代码生成器、动态代理框架和其他需要在运行时操纵字节码的场合。 2. **ASM Commons(asm-commons-2.2.jar)**:ASM Commons是ASM框架的一个扩展,它包含了一些额外的工具类和visitor,专门用于处理常见...

    asm-commons-3.0.jar.zip

    ASM是一个低级别的字节码操纵和分析框架,它可以直接生成和修改Java类的字节码。ASM的核心API包括ClassReader和ClassWriter,前者用于读取字节码,后者则负责生成新的字节码。ASM Commons在此基础上,提供了一些更...

    asm-tree-3.3.1.jar.zip

    首先,ASM是一个Java字节码操纵和分析框架,它可以直接用来动态生成类或者增强已有类的功能。ASM Tree库则是ASM框架中的一个模块,它的主要作用是将ASM低级别的字节码操作转化为直观的树形结构,便于开发者理解和...

    asm-3.3.jar.zip

    1. **字节码操纵**:ASM允许开发者生成和修改Java字节码,可以用来创建动态代理、插桩或在运行时改变类的行为。 2. **高性能**:由于直接操作字节码,ASM提供了非常高的性能,尤其适合需要高性能字节码处理的场景。 ...

    asm-util-3.0.jar.zip

    3. **字节码操纵**:在类加载到JVM之前,ASM可以在字节码级别进行修改,比如插入日志、性能监控、安全检查等代码。 描述中提到的"asm, util, 3.0, jar.zip包下载, 依赖包"表明asm-util-3.0.jar可能是一个包含了ASM...

    asm-9.0.jar

    ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件...

    asm-debug-all-5.0.2.zip

    【标题】"asm-debug-all-5.0.2.zip"是一个包含ASM库的调试版本的压缩包,ASM是一个流行的Java字节码操控和分析框架。这个5.0.2版本的ASM提供了对Java字节码的深度操作能力,主要用于动态代理、代码分析以及虚拟机...

    asm-attrs-1.4.1.jar.zip

    总之,ASM-Attrs-1.4.1.jar.zip提供的ASM库组件是Java字节码处理的重要工具,它能够帮助开发者深入理解和操纵Java字节码,实现各种高级功能。而理解并遵循其许可证规定,是尊重开源社区规则,保证项目合法性的重要...

    代码生成工具asm-3.2

    ASM-3.2是这个工具的一个版本,主要用于动态程序分析和字节码操纵。这个框架广泛应用于许多领域,如代码混淆、性能监控、动态代理以及字节码级别的编程。 **ASM的概述** ASM是一个低级别的库,它可以解析、生成和...

    asm-util-2.2.jar.zip

    1. **asm**:ASM是这个库的核心,它是Java字节码操纵和分析框架。ASM提供了一种直接在类文件级别操作的方法,可以用来创建、修改或分析Java类和接口。 2. **util**:这里的“util”可能指的是ASM的“Util”模块,它...

    asm-3.2-bin.zip

    ASM,全称是“Abstract Syntax Notation One”,是一种低级字节码操纵和分析框架,主要用于生成和解析Java字节码。ASM库被广泛应用于动态代理、代码分析、字节码增强等领域,尤其是在Java框架如Hibernate、Spring ...

    asm-attrs-20041228.180559.jar.zip

    标题中的"asm-attrs-20041228...总结来说,这个压缩包提供的ASM库版本和相关属性处理模块,是Java字节码处理和分析的核心工具,适用于需要底层操纵Java字节码的开发者。而许可证文件则确保了合法合规地使用这个开源库。

    asm-commons-3.3.zip_asm-commons-3.3.jar

    ASM Commons 是一个与Java字节码操作相关的库,它是ASM框架的一个扩展,专注于提供更高级别的抽象和便利性,使得开发者...通过理解和熟练使用ASM Commons,开发者可以更高效地操纵字节码,以满足复杂的应用场景需求。

    Java字节码操纵框架 asm-3.1组件包大集合

    ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class ...

    asm-xml-20041228.180559.jar.zip

    ASM是一个流行的Java字节码操纵和分析框架,常用于动态代理、代码生成和字节码级别的性能优化。 首先,我们来深入了解ASM库。ASM是一个开源项目,它提供了对Java字节码的低级别访问,允许开发人员在运行时动态生成...

Global site tag (gtag.js) - Google Analytics