ASM是一款操作class文件流的工具类,效率大大高于普通Java代码编译成class的方式。操作class流的方式其实就是通过手动操作jvm的指令集,来生成或修改class文件流。
众所周知普通Java代码通过javac编译生成class文件后,再通过javap -v 即可查看反编译的类似汇编代码。而asm的实现方式就是完成这样的汇编代码。
如上图所示,就是方法HelloWorld的反汇编代码。
ASM API参考:http://tool.oschina.net/apidocs/apidoc?api=asm
其中jvm操作码可参考《jvm规范》中文版
主要的3个类:
1、ClassVisitor
访问类的抽象类
2、ClassWriter
继承了ClassVisitor,实现了ClassVisitor,修改class类都是通过这个类
3、ClassReader
主要使用步骤:
ClassReader cr = new ClassReader(inputStream);//创建一个对象,接受一个被修改class类的inputStream,若只是生成class类传0
ClassWriter cw = new ClassWriter(cr, 0);//创建一个修改class类的对象,接受ClassReader对象参数,在ClassWriter构造方法中保存了对象cr的引用
ClassVisitor cv = new ClassVisitor(Opcodes.ASM4, cw) {//通过内部类方式,真正的修改动作在重写方法中实现
@Override
这里重写需要修改class类的方法
}
cr.accept(cv, 0);//对象cr接受一个cv对象并完成class的修改
cw.toByteArray();//返回class修改完后生成新的class字节流
以上,还存在另外一种调用方式:
ClassWriter classWriter = new ClassWriter(0);
classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, className, null,
“java/lang/Object”, null);
MethodVisitor initVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, “”,
“()V”, null, null);
initVisitor.visitCode();//访问开始
initVisitor.visitVarInsn(Opcodes.ALOAD, 0);//this指针入栈
initVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, “java/lang/Object”, “”,
“()V”);//调用构造函数
initVisitor.visitInsn(Opcodes.RETURN);
initVisitor.visitMaxs(1, 1);//设置栈长、本地变量数
initVisitor.visitEnd();//访问结束
通过手动调用jvm指令集的方式完成class流的操作,实际上第一种方式的重写方法中也是调用了这些方法。
针对修改class文件使用到jvm的指令集,指令参考:https://blog.csdn.net/xiangpi99/article/details/70237672 和 《jvm规范》