ASM第一篇【HelloWorld】

简介:ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

Asm架构整体都围绕着两个接口,即ClassVisitor 和 CodeVisitor,它们能访问每个类的方法,成员变量,包含在每个方法中的字节码指令。ClassReader用来读取class文件;ClassWriter类用来写生成的Class文件。

为了修改已经存在的class,你必须使用分析class文件的ClassReader,类的修正器和写class文件的ClassWriter。 类的修正器就是一个ClassVisitor,它可以委派一部分工作到其他的ClassVisitor,但是为了实现预期的修改步骤,它将改变一些参数的 值,或者调用一些其他方法。为了比较容易的实现这种类的修正器,ASM提供了一个ClassAdapter和CodeAdapter,这两个适配器类分别 实现了ClassVistor和CodeVistor接口。

ASM官网:http://asm.ow2.org/

ASM最新版本是4.0 下载地址:http://forge.ow2.org/projects/asm/

学习ASM最好能下载ASM的一个eclipse的插件,这个插件能看你当前类如果用ASM来生成代码应该怎样写。插件下载地址:http://download.forge.objectweb.org/eclipse-update/

 

下面用ASM写一个HelloWorld,体验一下哈。

import java.io.FileOutputStream;
import java.lang.reflect.Method;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class HelloWorld extends ClassLoader {
 /**
  * 如何使用ASM动态生成一个类,并打印出HelloWorld!
  * 
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  // 创建一个ClassWriter来写示例类,这个类继承Object
  ClassWriter cw = new ClassWriter(0);
  /*
   * 第一个参数:JDK版本 
   * 第二个参数:这个类的访问标记 
   * 第三个参数:这个类的名字
   * 第四个参数:这个类的签名,当这个类没有继承或者实现一个接口的时候可以为空。 
   * 第五个参数:当前类父类的名字 接口的父类是Object当该类是Object的时候为空 
   * 第六个参数:接口的名字 可以为空
   */
  cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, "Example", null, "java/lang/Object", null);
  /*
   * 创建一个写默认构造器的MethodWriter 
   * 第一个参数:方法的访问标记 
   * 第二个参数:方法名称 
   * 第三个参数:方法的描述符号
   * 第四个参数:方法签名(当方法参数 返回类型 以及异常没有用到类属性的时候可以为空) 
   * 第⑤个参数:异常名称
   */
  MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
  // 压入this变量
  mv.visitVarInsn(Opcodes.ALOAD, 0);
  // 执行父类构造器
  mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
  mv.visitInsn(Opcodes.RETURN);
  // 这段代码使用最多一个堆元素 和一个 局部变量
  mv.visitMaxs(1, 1);
  mv.visitEnd();
  // 创建一个main方法的MethodWriter
  mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
  // 调用System类的PrintStream类的out
  mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
  // 压入"Hello World!" 常量
  mv.visitLdcInsn("Hello World!");
  // 执行定义在PrintStream中的println方法
  mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
  mv.visitInsn(Opcodes.RETURN);
  // 使用两个堆和两个局部变量
  mv.visitMaxs(2, 2);
  // 获取Example类的字节码并且动态加载它。
  byte[] code = cw.toByteArray();
  FileOutputStream fos = new FileOutputStream("Example.class");
  fos.write(code);
  fos.close();
  HelloWorld loader = new HelloWorld();
  Class<?> exampleClass = loader.defineClass("Example", code, 0, code.length);
  // 使用动态生成的类打印HelloWorld
  Method method = exampleClass.getMethods()[0];
  method.invoke(null, new Object[] { null });
 }
}

 

你可能感兴趣的:(java,exception,ClassLoader,object,null,Class)