ASM 之 Core API 和 Tree API 配合使用

ASM Core API 和 Tree API 比较

ASM 提供两种处理Class 字节码的 API,Core API 和 Tree API。

  • Core API
    Core API 是基于访问者模式设计的,使用起来速度快占用内存小,但是处理起来非常的不灵活。
  • Tree API
    Tree API 是基于对象模式设计的,使用起来非常的灵活,但是处理处理速度慢,占用内存大。

Core API 和 Tree API 有各自的有缺点,两者配合使用发挥各自的优势,才能达到更好的效果。

ASM MethodNode 解析

1
public class MethodNode extends MethodVisitor {

MethodNode 是Tree API 重要的 Class,用来处理方法。MethodNode 继承了MethodVisitor 类,所以 MethodNode 可以用在 Core API 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(an);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(an);
}
return an;
}

以上的代码为 MethodNode 处理注解的方法,其把所有的注解信息,存储在了自己的数据结构中, 所以如果直接使用MethodNode 当做 Core API 使用,下游的MethodVisitor 是不会被触发的。访问者模式也就失效了。

ASM Core API 和 Tree API 结合思路

MethodNode 读取的数据会存储在自己的数据结构中,当读取完成后,也就是在 visitEnd的时候手动 触发下游的 MethodVisitor,就是调用accept 方法。

参考 TryCatchBlockSorter 实现方式

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
39
40
41
42
43
44
// 继承 MethodNode 类,使用Tree API的功能
public class TryCatchBlockSorter extends MethodNode {

public TryCatchBlockSorter(final MethodVisitor mv, final int access,
final String name, final String desc, final String signature,
final String[] exceptions) {
this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions);
}

protected TryCatchBlockSorter(final int api, final MethodVisitor mv,
final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
super(api, access, name, desc, signature, exceptions);
this.mv = mv;
}

@Override
public void visitEnd() {
// 内容读取完成后,修改方法体的内容,Tree API 处理起来十分的灵活
Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() {

public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
int len1 = blockLength(t1);
int len2 = blockLength(t2);
return len1 - len2;
}

private int blockLength(TryCatchBlockNode block) {
int startidx = instructions.indexOf(block.start);
int endidx = instructions.indexOf(block.end);
return endidx - startidx;
}
};
Collections.sort(tryCatchBlocks, comp);

for (int i = 0; i < tryCatchBlocks.size(); ++i) {
tryCatchBlocks.get(i).updateIndex(i);
}
//方法修改完成后,手动触发下游的 MethodVisitor,完成和 Core API的结合
if (mv != null) {
accept(mv);
}
}
}