ASM 是一款广为使用的字节码操作库,很多 Gradle Transform 会用它对编译后的代码进行插桩和修改操作,源码仓库在 GitLab
Visitor pattern represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
访问者模式 是一种将数据结构与数据操作分离的设计模式,它封装一些作用于某种数据结构中的各元素的操作,可以在不改变数据结构的前提下定义作用于这些元素的新的操作,属于行为型模式
访问者模式被称为最复杂的设计模式,并且使用频率不高,设计模式的作者也评价为:大多情况下,你不需要使用访问者模式,但是一旦需要使用它时,那就真的需要使用了,其基本思想是:
accept() 方法用来接受访问者对象的访问accept() 方法可以接收不同的访问者对象,然后在内部将自己(元素)转发到接收到的访问者对象的 visit() 方法内,访问者内部对应类型的 visit() 方法就会得到回调执行accept() 方法,第二次是对元素的分发 visit() 方法,才最终将一个具体的元素传递到一个具体的访问者,如此一来就解耦了数据结构与操作,且数据操作不会改变元素状态访问者模式的核心是解耦数据结构与数据操作,使得对元素的操作具备优秀的扩展性,可以通过扩展不同的数据操作类型(访问者)实现对相同元素集的不同的操作

整个 ASM 库的核心概念是访问者模式
字节码(.class 文件)是一种固定格式的文件,它的数据结构如下图,对应的解析逻辑定义在 ClassReader,然后提供了 ClassVisitor、MethodVisitor、FieldVisitor 和 AnnotationVisitor 等各种 Visitor 来访问
ClassVisitor 提供了以下的 visitor 方法去访问对应的数据结构,下面以 java.lang.String 为例
public abstract class ClassVisitor {
public void visit(
int version, // 52
int access, // 49
String name, // java/lang/String
String signature, // Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/Comparable<Ljava/lang/String;>;Ljava/lang/CharSequence;
String superName, // java/lang/Object
String[] interfaces // java/io/Serializable,java/lang/Comparable,java/lang/CharSequence
)
// access:18, name:value, descriptor:[C, signature:null, value:null
// access:26, name:serialVersionUID, descriptor:J, signature:null, value:-6849794470754667710
// access:25, name:CASE_INSENSITIVE_ORDER, descriptor:Ljava/util/Comparator;, signature:Ljava/util/Comparator<Ljava/lang/String;>;, value:null
// ...
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value)
// access:1, name:<init>, descriptor:(Ljava/lang/String;)V, signature:null, exceptions:null
// access:1, name:<init>, descriptor:([BIILjava/lang/String;)V, signature:null, exceptions:java/io/UnsupportedEncodingException
// access:1, name:getBytes, descriptor:(Ljava/lang/String;)[B, signature:null, exceptions:java/io/UnsupportedEncodingException
// access:9, name:valueOf, descriptor:(Ljava/lang/Object;)Ljava/lang/String;, signature:null, exceptions:null
// ...
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions)
// name:java/lang/String$CaseInsensitiveComparator, outerName:java/lang/String, innerName:CaseInsensitiveComparator, access:10
public void visitInnerClass(String name, String outerName, String innerName, int access)
public void visitSource(String source, String debug)
public ModuleVisitor visitModule(String name, int access, String version)
public void visitNestHost(String nestHost)
public void visitOuterClass(String owner, String name, String descriptor)
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible)
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible)
public void visitAttribute(Attribute attribute)
public void visitNestMember(String nestMember)
public void visitPermittedSubclass(String permittedSubclass)
public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature)
public void visitEnd()
}
描述符(descriptor)的规则和例子如下图:


interface Opcodes {
// Java ClassFile versions (the minor version is stored in the 16 most significant bits, and the
// major version in the 16 least significant bits).
int V1_1 = 3 << 16 | 45;
int V1_2 = 0 << 16 | 46;
int V1_3 = 0 << 16 | 47;
int V1_4 = 0 << 16 | 48;
int V1_5 = 0 << 16 | 49;
int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51;
int V1_8 = 0 << 16 | 52;
int V9 = 0 << 16 | 53;
int V10 = 0 << 16 | 54;
int V11 = 0 << 16 | 55;
int V12 = 0 << 16 | 56;
int V13 = 0 << 16 | 57;
int V14 = 0 << 16 | 58;
int V15 = 0 << 16 | 59;
int V16 = 0 << 16 | 60;
int V17 = 0 << 16 | 61;
int V18 = 0 << 16 | 62;
int V19 = 0 << 16 | 63;
/**
* Version flag indicating that the class is using 'preview' features.
*
* <p>{@code version & V_PREVIEW == V_PREVIEW} tests if a version is flagged with {@code
* V_PREVIEW}.
*/
int V_PREVIEW = 0xFFFF0000;
}
version 是 class 文件格式的版本号,有如下版本号的定义:
interface Opcodes {
// Access flags values, defined in
// - <https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1>
// - <https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5-200-A.1>
// - <https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6-200-A.1>
// - <https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25>
int ACC_PUBLIC = 0x0001; // class, field, method
int ACC_PRIVATE = 0x0002; // class, field, method
int ACC_PROTECTED = 0x0004; // class, field, method
int ACC_STATIC = 0x0008; // field, method
int ACC_FINAL = 0x0010; // class, field, method, parameter
int ACC_SUPER = 0x0020; // class
int ACC_SYNCHRONIZED = 0x0020; // method
int ACC_OPEN = 0x0020; // module
int ACC_TRANSITIVE = 0x0020; // module requires
int ACC_VOLATILE = 0x0040; // field
int ACC_BRIDGE = 0x0040; // method
int ACC_STATIC_PHASE = 0x0040; // module requires
int ACC_VARARGS = 0x0080; // method
int ACC_TRANSIENT = 0x0080; // field
int ACC_NATIVE = 0x0100; // method
int ACC_INTERFACE = 0x0200; // class
int ACC_ABSTRACT = 0x0400; // class, method
int ACC_STRICT = 0x0800; // method
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner
int ACC_MANDATED = 0x8000; // field, method, parameter, module, module *
int ACC_MODULE = 0x8000; // class
}
access 是修饰符控制位的组合,有以下控制位:
MethodVisitor.visitXXX 方法调用