ASM架构
ASM是围绕事件生产者(class parser)、事件消费者(class writer)和各种预定义的事件过滤器的架构。架构图如下所示:

导入ASM库
1 2 3 4 5 6
| dependencies { implementation 'org.ow2.asm:asm:9.4' implementation 'org.ow2.asm:asm-commons:9.4' implementation 'org.ow2.asm:asm-util:9.4' }
|
Class结构
简述
类源码与已编译类之间是有许多不同之处的:
- 已编译类只能描述一个类,当源码包含几个类,例如一个源码包含一个类,其中还有一个内部类。它们会被编译成两个类文件:一个主类,一个内部类。主类文件包含它的内部类的引用,并且定义在方法内部的内部类包含对其闭包函数的引用。
- 已编译类不包含注释。
- 已编译类不包含
package和import模块,因此所有的类型名字都必须是全量的。
类结构的描述:

Class内部描述
类型描述
| Java类型 |
类型描述 |
| boolean |
Z |
| char |
C |
| byte |
B |
| short |
S |
| int |
I |
| float |
F |
| long |
J |
| double |
D |
| Object |
Ljava/lang/Object; |
| int[] |
[I |
| Object[][] |
[[Ljava/lang/Object; |
方法描述
| 方法源码 |
方法描述 |
| void m(int i, float f) |
(IF)V |
| int m(Object o) |
(Ljava/lang/Object;)I |
| int[] m(int i, String s) |
(ILjava/lang/String;)[I |
| Object m(int[] i) |
([I)Ljava/lang/Object; |
ClassVisitor
ClassVisitor类结构
1 2 3 4 5 6 7 8 9 10 11 12 13
| public abstract class ClassVisitor { public ClassVisitor(int api); public ClassVisitor(int api, ClassVisitor cv); public void visit(int version, int access, String name, String signature, String superName, String[] interfaces); public void visitSource(String source, String debug); public void visitOuterClass(String owner, String name, String desc); AnnotationVisitor visitAnnotation(String desc, boolean visible); public void visitAttribute(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); public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions); void visitEnd(); }
|
ClassVisitor类方法的调用必须随着下面的顺序:
1
| visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )* (visitInnerClass | visitField | visitMethod )* visitEnd
|
FieldVisitor类结构
1 2 3 4 5 6 7
| public abstract class FieldVisitor { public FieldVisitor(int api); public FieldVisitor(int api, FieldVisitor fv); public AnnotationVisitor visitAnnotation(String desc, boolean visible); public void visitAttribute(Attribute attr); public void visitEnd(); }
|
解析类
ClassReader能够解析存在的class,接下来一个例子是一个ClassPrinter用来打印访问类的信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class ClassPrinter: ClassVisitor(Opcodes.ASM5) { override fun visit( version: Int, access: Int, name: String?, signature: String?, superName: String?, interfaces: Array<out String>? ) { println("$name extends $superName {") } override fun visitField( access: Int, name: String?, descriptor: String?, signature: String?, value: Any? ): FieldVisitor? { println(" $descriptor $name") return null; } override fun visitMethod( access: Int, name: String?, descriptor: String?, signature: String?, exceptions: Array<out String>? ): MethodVisitor? { println(" $name $descriptor") return null } override fun visitEnd() { println("}") } }
|
然后将ClassReader和ClassPrinter结合起来。
1 2 3
| val cp = ClassPrinter(); val cr = ClassReader("java.lang.Runnable") cr.accept(cp, 0)
|
整个事件从accept()方法产生,然后依次调用ClassPrinter中的方法,并打印相关信息。
生成类
通过ClassWriter可以生成类,看以下的接口,我们将通过ClassWriter生成这样一个类:
1 2 3 4 5 6
| public interface Comparable extends Object { int LESS = -1; int EQUAL = 0; int GREATER = 1; int compareTo(Object o); }
|
生成这样一个接口只需要调用ClassVisitor六个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13
| val cw = ClassWriter(0) cw.visit( V1_8, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "com/bravestsnail/router/asm/Comparable", null, "java.lang.Object", arrayOf() ) cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I", null, -1).visitEnd() cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I", null, 0).visitEnd() cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I", null, 1).visitEnd() cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo", "(Ljava/lang/object;)I", null, null).visitEnd() cw.visitEnd() val b = cw.toByteArray()
|
第二行代码代表的意义:
定义一个com/bravestsnail/router/asm/Comparable,其java版本1.8,修饰符为public+abstract+interface代表是一个接口,其没有泛型,父类为java.lang.Object, 接口列表为空。
接下来三行定义了三个静态常量,调用visitEnd()是代表立即结束FieldVisitor的访问。
接下来一行定义了compareTo抽象方法。
转换类
看以下转换类的简单示例:
1 2 3 4 5 6
| byte[] b1 = ...; ClassWriter cw = new ClassWriter(0);
ClassVisitor cv = new ClassVisitor(ASM4, cw) { }; ClassReader cr = new ClassReader(b1); cr.accept(cv, 0); byte[] b2 = cw.toByteArray();
|

上面是转换链,由Reader产生事件,Adapter对这些进行转换,最终转换的结果在Writer重建。
接下来看一个转换java版本的Adapter:
1 2 3 4 5 6 7 8
| public class ChangeVersionAdapter extends ClassVisitor { public ChangeVersionAdapter(ClassVisitor cv) { super(ASM4, cv); } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { cv.visit(V1_5, access, name, signature, superName, interfaces); } }
|
上面的类在visit()方法中对该事件进行了转发,并且修改java版本为1.5。
看看整个过程的时序图:

优化
当ClassReader和ClassWriter互相持有对方的引用,将会执行一项优化,直接复制ClassReader中不需要转换的字节数组数据到ClassWriter
移除类成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class RemoveDebugAdapter(cv: ClassVisitor?) : ClassVisitor(ASM4, cv) { fun visitSource(source: String?, debug: String?) {} fun visitOuterClass(owner: String?, name: String?, desc: String?) {} fun visitInnerClass( name: String?, outerName: String?, innerName: String?, access: Int ) {} fun visitMethod( access: Int, name: String, desc: String, signature: String?, exceptions: Array<String?>? ): MethodVisitor? { return null } }
|
移除类成员可以通过不转发相应事件或者返回null。
添加类成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class AddFieldAdapter( cv: ClassVisitor?, private val fAcc: Int, private val fName: String, private val fDesc: String ) : ClassVisitor(ASM4, cv) { private var isFieldPresent = false fun visitField( access: Int, name: String, desc: String?, signature: String?, value: Any? ): FieldVisitor { if (name == fName) { isFieldPresent = true } return cv.visitField(access, name, desc, signature, value) } fun visitEnd() { if (!isFieldPresent) { val fv: FieldVisitor = cv.visitField(fAcc, fName, fDesc, null, null) if (fv != null) { fv.visitEnd() } } cv.visitEnd() } }
|
类分析工具
TraceClassVisitor
追踪打印类结构
CheckClassAdapter
检查生成的类
ASMifier
将class文件转换成ASM代码
Method结构