简介
FiedVisitor是用来在访问类的域字节码过程中创建域或者修改域字节码信息的;
MethodVisitor是用来在访问类的方法字节码过程中创建方法或者修改方法字节码信息从而实现改变方法行为;
FieldVisitor
FieldVisitor也是有一定访问顺序的,如下:
其访问顺序为:
( visitAnnotation | visitTypeAnnotation| visitAttribute )* visitEnd
()*中可以访问多次,而visitEnd在访问结束时必须访问一次
FieldVisitor方法解析:
- visitAnnotation:访问域的注解;
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (fv != null) {
return fv.visitAnnotation(descriptor, visible);
}
return null;
}
其中
descriptor表示注解类的描述,即注解类的描述:如“Ljava/lang/JavaBean”等;
visible表示该注解运行时是否可见;
- visitTypeAnnotation:访问域的类型上的注解
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
if (api < Opcodes.ASM5) {
throw new UnsupportedOperationException("This feature requires ASM5");
}
if (fv != null) {
return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
return null;
}
- visitAttribtue:访问域属性
- visitEnd:域访问完成后必须调用该方法;
MethodVisitor方法解析
MethodVisitor其方法访问顺序如下:
( visitParameter )*
[ visitAnnotationDefault ]
( visitAnnotation |visitAnnotableParameterCount | visitParameterAnnotation
visitTypeAnnotation | visitAttribute )*
[ visitCode ( visitFrame | visitInsn | visitLabel | visitInsnAnnotation | visitTryCatchBlock | visitTryCatchAnnotation | visitLocalVariable |
visitLocalVariableAnnotation | visitLineNumber )* visitMaxs ]
visitEnd
()*表示可以调用任意次;
[]表示里面的方法最多调用一次
- visitParameter:访问方法一个参数
public void visitParameter(final String name, final int access) {
if (api < Opcodes.ASM5) {
throw new UnsupportedOperationException(REQUIRES_ASM5);
}
if (mv != null) {
mv.visitParameter(name, access);
}
}
name表示参数名称;
access表示参数访问类型如final,synthetick,MANDATED;
- visitAnnotationDefualt:访问注解接口方法的默认值;
- visitAnnotaion:访问方法的一个注解;
- visitTypeAnnotation:访问方法签名上的一个类型的注解;
- visitAnnotableParameterCount:访问注解参数数量,就是访问方法参数有注解参数个数;
- visitParameterAnnotation:访问参数的注解,返回一个AnnotationVisitor可以访问该注解值;
- visitAttribute:访问方法属性;
- visitCode:开始访问方法代码,此处可以添加方法运行前拦截器;
- visitFrame:访问方法局部变量的当前状态以及操作栈成员信息,方法栈必须是expanded 格式或者compressed格式,该方法必须在visitInsn方法前调用;
- visitIntInsn:访问数值类型指令
public void visitIntInsn(final int opcode, final int operand) {
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
}
opcode表示操作码指令,在这里opcode可以是Opcodes.BIPUSH,Opcodes.SIPUSH,Opcodes.NEWARRAY中一个;
operand表示操作数,
如果opcode 为BIPUSH,那么operand value必须在Byte. minValue和Byte.maxValue之间;
如果opcode为SIPUSH,那么operand value必须在Short.minValue和Short.minValue之间;
如果opcode为NEWARRAY,那么operand value 可以取下面中一个:
Opcodes.T_BOOLEN,OPcodes.T_BYTE,OPCODES.T_CHAR,OPcodes.T_SHORT,OPcodes.T_INT,OPcodes.T_FLOAT,Opcodes.T_DOUBLE,Opcodes.T_LONG;
- visitVarInsn:访问本地变量类型指令
public void visitVarInsn(final int opcode, final int var) {
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
}
var表示需要访问的变量;
opcode:操作码可以是LOAD,STORE,RET中一种;
- visitTypeInsn:访问类型指令,类型指令会把类的内部名称当成参数Type
public void visitTypeInsn(final int opcode, final String type) {
if (mv != null) {
mv.visitTypeInsn(opcode, type);
}
}
opcode:操作码为NEW ,ANEWARRAY,CHECKCAST,INSTANCEOF;
type:对象或者数组的内部名称,可以通过Type.getInternalName()获取;
- visitFieldInsn:域操作指令,用来加载或者存储对象的Field;
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, descriptor);
}
}
- visitMethodInsn:访问方法操作指令
public void visitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces requires ASM5");
}
visitMethodInsn(opcode, owner, name, descriptor);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
}
opcode:为INVOKESPECIAL,INVOKESTATIC,INVOKEVIRTUAL,INVOKEINTERFACE;
owner:方法拥有者的名称;
name:方法名称;
descriptor:方法描述,参数和返回值;
isInterface;是否是接口;
- visitDynamicInsn:访问动态类型指令;
- visitJumpInsn:访问比较跳转指令;
public void visitJumpInsn(final int opcode, final Label label) {
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
}
opcode: IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
label:跳转目的label;
- visitLabelInsn:访问label,当会在调用该方法后访问该label标记一个指令;
- visitLdcInsn:访问ldc指令,也就是访问常量池索引;
public void visitLdcInsn(final Object value) {
if (api < Opcodes.ASM5
&& (value instanceof Handle
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
throw new UnsupportedOperationException(REQUIRES_ASM5);
}
if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
throw new UnsupportedOperationException("This feature requires ASM7");
}
if (mv != null) {
mv.visitLdcInsn(value);
}
}
value:必须是非空的Integer,Float,Double,Long,String,或者对象的Type,Array的Type,Method Sort的Type,或者Method Handle常量中的Handle,或者ConstantDynamic;
- visitIincInsn:访问本地变量索引增加指令;
public void visitIincInsn(final int var, final int increment) {
if (mv != null) {
mv.visitIincInsn(var, increment);
}
}
var:表示本地变量的索引
- visitTableSwitchInsn:访问跳转指令;
- visitLookupSwitchInsn:访问查询跳转指令;
- visitMultiANewArrayInsn:访问多维数组指令;
- visitInsnAnnotation:访问指令注解,必须在访问注解之后调用;
- visitTryCatchBlock:方法try--catch块;
- visitTryCatchBAnnotation:访问try...catch块上异常处理的类型注解,必须在调用visitTryCatchBlock之后调用;
- visitLocalVariable:访问本地变量描述;
public void visitLocalVariable(
final String name,
final String descriptor,
final String signature,
final Label start,
final Label end,
final int index) {
if (mv != null) {
mv.visitLocalVariable(name, descriptor, signature, start, end, index);
}
}
name:本地变量名称;
desriptor:本地变量类型描述;
signature:本地变量类型签名;
start:关联该本地变量范围的第一个指令的位置;
end:关联该本地变量范围的最后一个指令的位置:
index:本地变量的索引;
- visitLineNumber:访问行号描述;
- visitMaxs:访问操作数栈最大值和本地变量表最大值;