MethodVisitor介绍
通过调用ClassVisitor类的visitMethod()方法将返回一个MethodVisitor类型对象。
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions);
在本文中,我们将MethodVisitor类别介绍:
┌─── ClassReader │ │ │ ┌─── FieldVisitor ┌─── asm.jar ───────────┼─── ClassVisitor ───┤ │ │ └─── MethodVisitor │ │ │ │ ┌─── FieldWriter ┌─── Core API ───┤ └─── ClassWriter ────┤ │ │ └─── MethodWriter │ ├─── asm-util.jar │ │ ObjectWeb ASM ───┤ └─── asm-commons.jar │ │ │ ┌─── asm-tree.jar └─── Tree API ───┤ └─── asm-analysis.jar
1. MethodVisitor类
就类结构而言,MethodVisitor类与ClassVisitor类和FieldVisitor类别非常相似。
1.1. class info
第一部分,MethodVisitor类是一个abstract类。
public abstract class MethodVisitor {
}
1.2. fields
第二部分,MethodVisitor类定义的字段是什么?
public abstract class MethodVisitor {
protected final int api; protected MethodVisitor mv; }
1.3. constructors
第三个部分,MethodVisitor类定义的结构方法有哪些?
public abstract class MethodVisitor {
public MethodVisitor
(
final
int api
)
{
this
(api
,
null
)
;
}
public
MethodVisitor
(
final
int api
,
final
MethodVisitor methodVisitor
)
{
this
.api
= api
;
this
.mv
= methodVisitor
;
}
}
1.4. methods
第四个部分,MethodVisitor类定义的方法有哪些。在MethodVisitor类当中,定义了许多的visitXxx()方法,我们列出了其中的一些方法,内容如下:
public abstract class MethodVisitor {
public void visitCode();
public void visitInsn(final int opcode);
public void visitIntInsn(final int opcode, final int operand);
public void visitVarInsn(final int opcode, final int var);
public void visitTypeInsn(final int opcode, final String type);
public void visitFieldInsn(final int opcode, final String owner, final String name, final String descriptor);
public void visitMethodInsn(final int opcode, final String owner, final String name, final String descriptor,
final boolean isInterface);
public void visitInvokeDynamicInsn(final String name, final String descriptor, final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments);
public void visitJumpInsn(final int opcode, final Label label);
public void visitLabel(final Label label);
public void visitLdcInsn(final Object value);
public void visitIincInsn(final int var, final int increment);
public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels);
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels);
public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions);
public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type);
public void visitMaxs(final int maxStack, final int maxLocals);
public void visitEnd();
// ......
}
- visitParameter:访问方法一个参数
- visitAnnotationDefualt:访问接口方法的默认值
- visitAnnotation:访问方法的一个注解
- visitTypeAnnotation:访问方法签名上的一个类型的注解
- visitAnnotableParameterCount:访问注解参数数量,就是访问方法参数有注解参数个数;
- visitParameterAnnotation:访问参数的注解,返回一个- AnnotationVisitor可以访问该注解值;
- visitAttribute:访问方法属性;
- visitCode:开始访问方法代码,此处可以添加方法运行前拦截器;
- visitFrame:访问方法局部变量的当前状态以及操作栈成员信息,方法栈必须是expanded格式或者compressed格式,该方法必须在visitInsn方法前调用;
- visitIntlnsn:访问数值类型指令
- visitVarInsn:访问本地变量类型指令
- visitTypeInsn:访问类型指令,类型指令会把类的内部名称当成参数Type
- visitFieldInsn:域操作指令,用来加载或者存储对象的Field;
- visitMethodInsn:访问方法操作指令
- visitDynamiclnsn:访问动态类型指令;
- visitJumplnsn:访问比较跳转指令;
- visitlinclnsn:访问本地变量索引增加指令;
- visitTableSwitchInsn:访问跳转指令;
- visitLookupSwitchInsn:访问查询跳转指令;
- visitMultiANewArrayInsn:访问多维数组指令;
- visitlnsnAnnotation:访问指令注解,必须在访问注解之后调用;
- visitTryCatchBlock:方法try-catch块;
- visitTryCatchBAnnotation:访问try.catch:块上异常处理的类型注解,必须在调用visitTryCatchBlock之后调用;
- visitLocalVariable:访问本地变量描述,
- visitLineNumber:访问行号描述;
- visitMaxs:访问操作数栈最大值和本地变量表最大值;
对于这些visitXxx()方法,它们分别有什么作用呢?我们有三方面的资料可能参阅:
- 第一,从ASM API的角度来讲,我们可以查看API文档,来具体了解某一个方法是要实现什么样的作用,该方法所接收的参数代表什么含义。
- 第二,从ClassFile的角度来讲,这些visitXxxInsn()方法的本质就是组装instruction的内容。我们可以参考Java Virtual Machine Specification的Chapter 6. The Java Virtual Machine Instruction Set部分。
- 第三,《Java ASM系列二:OPCODE》,主要是对opcode进行介绍。
2. 方法的调用顺序
在MethodVisitor类当中,定义了许多的visitXxx()方法,这些方法的调用,也要遵循一定的顺序。
(visitParameter)*
[visitAnnotationDefault]
(visitAnnotation | visitAnnotableParameterCount | visitParameterAnnotation | visitTypeAnnotation | visitAttribute)*
[
visitCode
(
visitFrame |
visitXxxInsn |
visitLabel |
visitInsnAnnotation |
visitTryCatchBlock |
visitTryCatchAnnotation |
visitLocalVariable |
visitLocalVariableAnnotation |
visitLineNumber
)*
visitMaxs
]
visitEnd
我们可以把这些visitXxx()方法分成三组:
- 第一组,在visitCode()方法之前的方法。这一组的方法,主要负责parameter、annotation和attributes等内容,这些内容并不是方法当中“必不可少”的一部分;在当前课程当中,我们暂时不去考虑这些内容,可以忽略这一组方法。
- 第二组,在visitCode()方法和visitMaxs()方法之间的方法。这一组的方法,主要负责当前方法的“方法体”内的opcode内容。其中,visitCode()方法,标志着方法体的开始,而visitMaxs()方法,标志着方法体的结束。
- 第三组,是visitEnd()方法。这个visitEnd()方法,是最后一个进行调用的方法。
对这些visitXxx()方法进行精简之后,内容如下:
[
visitCode
(
visitFrame |
visitXxxInsn |
visitLabel |
visitTryCatchBlock
)*
visitMaxs
]
visitEnd
这些方法的调用顺序,可以记忆如下:
- 第一步,调用visitCode()方法,调用一次。
- 第二步,调用visitXxxInsn()方法,可以调用多次。对这些方法的调用,就是在构建方法的“方法体”。
- 第三步,调用visitMaxs()方法,调用一次。
- 第四步,调用visitEnd()方法,调用一次。
┌─── visitCode()
│
│ ┌─── visitXxxInsn()
│ │
│ ├─── visitLabel()
├─── visitXxxInsn() ───┤
MethodVisitor ───┤ ├─── visitFrame()
│ │
│ └─── visitTryCatchBlock()
│
├─── visitMaxs()
│
└─── visitEnd()
3. 总结
本文是对MethodVisitor类进行了介绍,内容总结如下:
- 第一点,对于MethodVisitor类的各个不同部分进行介绍,以便从整体上来理解MethodVisitor类。
- 第二点,在MethodVisitor类当中,visitXxx()方法也需要遵循一定的调用顺序。
另外,需要注意两点内容:
- 第一点,ClassVisitor类有自己的visitXxx()方法,MethodVisitor类也有自己的visitXxx()方法,两者是不一样的,要注意区分。
- 第二点,ClassVisitor.visitMethod()方法提供的是“方法头”(Method Header)所需要的信息,它会返回一个MethodVisitor对象,这个MethodVisitor对象就用来实现“方法体”里面的代码逻辑。