是什么?
ASM是一个通用的Java字节码操作和分析框架。 它可以用于修改现有类或直接以二进制形式动态生成类。 ASM提供了一些常见的字节码转换和分析算法,可以从中构建自定义复杂转换和代码分析工具。 ASM提供与其他Java字节码框架类似的功能,但专注于性能。 因为它的设计和实现尽可能小而且快,所以它非常适合在动态系统中使用(但当然也可以以静态方式使用,例如在编译器中)。
ASM API
ASM API基于访问者模式,为我们提供了ClassVisitor,MethodVisitor,FieldVisitor API接口,每当ASM扫描到类字段是会回调visitField方法,扫描到类方法是会回调MethodVisitor,下面我们看一下API接口
ClassVisitor方法解析
public abstract class ClassVisitor {
......
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces);
//访问类字段时回调
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value);
//访问类方法是回调
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions);
public void visitEnd();
}
MethodVisitor方法解析
public abstract class MethodVisitor {
......
public void visitParameter(String name, int access);
//访问本地变量类型指令 操作码可以是LOAD,STORE,RET中一种;
public void visitIntInsn(int opcode, int operand);
//域操作指令,用来加载或者存储对象的Field
public void visitFieldInsn(int opcode, String owner, String name, String descriptor);
//访问方法操作指令
public void visitMethodInsn(int opcode, String owner, String name, String descriptor);
public void visitEnd();
}
ASM 使用Demo
java源码
public int add(int a,int b) {
return a+b+num1;
}
class字节码
public int add(int, int);
descriptor: (II)I
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3
0: iload_1
1: iload_2
2: iadd
3: aload_0
4: getfield #2 // Field num1:I
7: iadd
8: ireturn
LineNumberTable:
line 14: 0
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/wuba/asmdemo/Test;
0 9 1 a I
0 9 2 b I
ASM对应的API
mv = cw.visitMethod(ACC_PUBLIC, "add", "(II)I", null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 1);
mv.visitVarInsn(ILOAD, 2);
mv.visitInsn(IADD);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "com/wuba/asmdemo/Test", "num1", "I");
mv.visitInsn(IADD);
mv.visitInsn(IRETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "Lcom/wuba/asmdemo/Test;", null, l0, l1, 0);
mv.visitLocalVariable("a", "I", null, l0, l1, 1);
mv.visitLocalVariable("b", "I", null, l0, l1, 2);
mv.visitMaxs(2, 3);
mv.visitEnd();
可以看出ASM是在指令层次上操作字节码的,和class字节码更加接近。如果我们有些字节码操作的需求,ASM一定可以实现的。只是使用起来比较麻烦一些。这里强烈推荐一款ASM插件ASM ByteCode Outline。 可以一键生成对应的ASM API代码
参考
https://www.kancloud.cn/alex_wsc/android_plugin/471061
Jvm系列3-字节码指令 - Gityuan博客 | 袁辉辉的技术博客