ASM框架學習(三)-FieldVisitor和MethodVisitor

簡介

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:訪問操作數棧最大值和本地變量表最大值;
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,123評論 6 13
  • 第6章類文件結構 6.1 概述 6.2 無關性基石 6.3 Class類文件的結構 java虛擬機不和包括java...
    kennethan閱讀 967評論 0 2
  • Swift1> Swift和OC的區別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,136評論 1 32
  • 第二部分 自動內存管理機制 第二章 java內存異常與內存溢出異常 運行數據區域 程序計數器:當前線程所執行的字節...
    小明oh閱讀 1,204評論 0 2
  • 路是直的,人是彎的…… 路是彎的,人是直的…… 每個人的人生從路上消逝,從不回頭。而我們卻不能停下,不能回頭,不能...
    葉滿城閱讀 585評論 0 1