AMS使用指南
实战java虚拟机
ASM是一款java字节码的操作库,它在java领域是赫赫有名的函数库。不少著名的软件都依赖该库进行字节码操作。不少著名的软件都依赖该库进行字节码操作。比如,AspectJ,Clojure,Eclipse,spring以及CGLIB都是ASM的使用者。
引入ASM
可以到http://asm.objectweb.org/官方下载,
也可以直接引入maven依赖:
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-all</artifactId>
<version>5.0.2</version>
</dependency>
ASM体系结构
HelloWorld
public class AsmHelloWorld extends ClassLoader implements Opcodes {
public static void main(String[] args) throws IOException, InvocationTargetException, IllegalAccessException {
//定义一个叫做Example的类
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_6, ACC_PUBLIC, "Example", null, "java/lang/Object", null);
//生成默认的构造方法
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
//生成构造方法的字节码指令
mw.visitVarInsn(ALOAD, 0);
mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mw.visitInsn(RETURN);
mw.visitMaxs(1, 1);
mw.visitEnd();
//生成main方法 : public static void main(String args[]);
mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,"main","([Ljava/lang/String;)V",null,null);
//生成main方法中的字节码指令: System.out.println("hello world")
mw.visitFieldInsn(GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream;");
mw.visitLdcInsn("Hello world!");
mw.visitMethodInsn(INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/String;)V");
mw.visitInsn(RETURN);
mw.visitMaxs(2, 2);
//字节码生成完成
mw.visitEnd();
// 获取生成的class文件对应的二进制流
byte[] code = cw.toByteArray();
//将二进制流写到本地磁盘上
FileOutputStream fos = new FileOutputStream("Example.class"); //磁盘上生成Example.class文件
fos.write(code);
fos.close();
//直接将二进制流加载到内存中
AsmHelloWorld loader = new AsmHelloWorld();
Class<?> exampleClass = loader.defineClass("Example", code, 0, code.length);
//通过反射调用main方法
exampleClass.getMethods()[0].invoke(null, new Object[]{null});
}
}
解析
使用javap -v Example
public class Example
minor version: 0
major version: 50
flags: ACC_PUBLIC
Constant pool:
//...............略
{
public Example();
descriptor: ()V ####无参构造函数
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #18 // String Hello world!
5: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}