ASM 소스 코드 학습 의 ClassReader,ClassVisitor 와 ClassWriter 상세 설명

ASM
ASM 은 자바 에서 비교적 유행 하 는 바이트 코드 를 읽 는 라 이브 러 리 로 바이트 코드 를 바탕 으로 코드 를 분석 하고 변환 하 는 데 사용 된다.읽 기와 쓰기 과정 에서 CGLIB 와 같은 컴 파일 된 바이트 코드 를 강화 하거나 수정 하기 위해 사용자 정의 논 리 를 추가 할 수 있 습 니 다.ASM 은 실행 할 때 자바 류 를 생 성하 고 변환 하 는 데 사용 되 며 오프라인 처리 도 포함 된다.ASM 은 짧 고 간결 하 며 속도 가 빠 르 기 때문에 실행 할 때 동적 으로 바이트 코드 를 생 성하 거나 변환 할 때 프로그램 속도 에 미 치 는 영향 을 피 할 수 있 으 며 부피 가 작 기 때문에 많은 메모리 가 제 한 된 환경 에서 사용 할 수 있다.
ASM 의 주요 장점 은 다음 과 같은 몇 가지 측면 을 포함한다.
     1.또 하 나 는 작 지만 디자인 이 좋 고 모듈 화 된 API 이 며 사용 하기 쉽다.
     2.좋 은 문 서 를 가지 고 있 으 며 eclipse 플러그 인 도 있 습 니 다.
     3.최신 자바 버 전 을 지원 합 니 다.
     4.짧 고 날렵 하 며 빠 르 고 건장 하 다.
     5.새로운 사용자 에 게 지원 할 수 있 는 또 하나의 커 다란 사용자 커 뮤 니 티 입 니 다.
     6.오픈 소스 허 가 는 거의 모든 방식 으로 사용 할 수 있 습 니 다.
ASM 에 대한 상세 한 소 개 는 참고 할 수 있 습 니 다.자바 바이트 프레임 ASM 깊이 있 는 학습
ASM 코어 디자인 일람
ASM 의 핵심 실현 에서 다음 과 같은 몇 가지 종류,인터페이스org.objectweb.asm가 있다.
ClassReader 클래스:바이트 코드 의 읽 기와 분석 엔진.이 는 SAX 와 유사 한 이벤트 읽 기 메커니즘 을 사용 하여 이벤트 가 발생 할 때마다 등 록 된 ClassVisitor,AnnotationVisitor,FieldVisitor,MethodVisitor 를 호출 하여 해당 하 는 처 리 를 한다.
ClassVisitor 인터페이스:클래스 바이트 코드 를 읽 을 때 발생 하 는 이 벤트 를 정의 합 니 다.예 를 들 어 클래스 헤더 해석 완료,주해 해석,필드 해석,방법 해석 등 입 니 다.
AnnotationVisitor 인터페이스:주 해 를 해석 할 때 발생 하 는 이 벤트 를 정의 합 니 다.예 를 들 어 기본 값 형식의 주해,enum 값 형식의 주해,Array 값 형식의 주해,주해 값 유형의 주해 등 입 니 다.
FieldVisitor 인터페이스:필드 에 있 는 주 해 를 분석 하고 필드 와 관련 된 속성 을 분석 하 는 등 필드 를 분석 할 때 발생 하 는 이 벤트 를 정의 합 니 다.
MethodVisitor 인터페이스:방법 상의 주석,속성,코드 등 을 분석 할 때 발생 하 는 사건 을 정의 합 니 다.
ClassWriter 클래스:ClassVisitor 인 터 페 이 스 를 실현 하여 바이트 코드 를 맞 추 는 데 사용 합 니 다.
AnnotationWriter 클래스:AnnotationVisitor 인 터 페 이 스 를 실현 하여 관련 바이트 코드 를 맞 추 는 데 사용 합 니 다.
FieldWriter 클래스:필드 와 관련 된 바이트 코드 를 연결 하 는 데 사용 되 는 FieldVisitor 인 터 페 이 스 를 실현 합 니 다.
MethodWriter 클래스:MethodVisitor 인 터 페 이 스 를 실현 하여 연결 방법 과 관련 된 바이트 코드 를 사용 합 니 다.
SignatureReader 클래스:클래스 정의,필드 정의,방법 정의,로 컬 변수 정의 서명 에 대한 분석.Signature 는 범례 가 도입 되 어 범례 정 의 를 저장 할 때 메타 데 이 터 를 저장 합 니 다(이 메타 데 이 터 는 실행 할 때 지 워 지기 때 문 입 니 다).
SignatureVisitor 인터페이스:Signature 를 분석 할 때 발생 하 는 이벤트,예 를 들 어 정상 적 인 Type 파라미터,클래스 또는 인터페이스의 경계 등 을 정의 합 니 다.
SignatureWriter 클래스:SignatureVisitor 인 터 페 이 스 를 실현 하여 범례 와 관련 된 바이트 코드 를 맞 추 는 데 사용 합 니 다.
Attribute 클래스:바이트 코드 의 속성 클래스 추상.
ByteVector 클래스:바이트 바 이 너 리 저장 용기.
Opcodes 인터페이스:바이트 코드 명령 의 상수 정의
Type 클래스:유형 과 관련 된 상수 정의 및 그 에 기반 한 작업.
그들 사이 의 도표 관 계 는 다음 과 같다.

ClassReader 는 ASM 에서 가장 핵심 적 인 실현 으로 Class 바이트 코드 를 읽 고 해석 하 는 데 사 용 됩 니 다.
ClassReader 인 스 턴 스 를 구축 할 때 먼저 바이트 코드 바 이 너 리 배열 b 를 저장 한 다음 에 items 배열 을 만 듭 니 다.배열 의 길 이 는 바이트 배열 의 8,9 번 째 바이트 에서 지정 합 니 다.각 아 이 템 은 상수 탱크 항목 이 바이트 코드 배열 의 오프셋 에 1 을 추가 하 는 것 을 나타 낸다.FieldRef_Info、CONSTANT_MethodRef_Info、CONSTANT_InterfaceMethodRef_Info、CONSTANT_NameAndType_Info 는 그 유형의 바이트 가 5 개의 바이트 를 차지 하 는 것 을 포함 하고,다른 4 개의 바이트 가 2 개의 바이트 마다 필드,방법 등 이 있 는 클래스,그 이름,설명 자 는 현재 상수 탱크 에서 CONSTANTUtf8_Info 형식의 참조;CONSTANT_Integer_Info、CONSTANT_Float_Info 는 그 유형의 바이트 가 5 개의 바이트 를 차지 하고 다른 4 개의 바이트 가 대응 하 는 값 을 포함한다.CONSTANT_Class_Info、CONSTANT_String_Info 는 그 유형의 바이트 가 3 개의 바 이 트 를 차지 하 는 것 을 포함 하고,다른 두 바 이 트 는 현재 상수 탱크 인 CONSTANT 입 니 다.Utf8_Info 항목 의 색인;CONSTANT_Utf8_Info 형식 첫 번 째 바이트 표시 형식,두 번 째,세 번 째 바이트 가 이 항목 에 표 시 된 문자열 의 길이);CONSTANT_Double_Info、CONSTANT_Long_Info 에 형식 바이트 9 글자 추가 하기;maxStringLength 는 가장 긴 UTF 8 유형의 상수 탱크 항목 의 값 을 표시 합 니 다.CONSTANT 를 분석 하기 로 결정 합 니 다.Utf8_Info 형식 항목 에 가장 필요 한 문자 배열;header 는 상수 탱크 뒤의 바이트 번 호 를 나타 내 는 첫 번 째 바이트 입 니 다.
ClassReader 의 accept 방법 을 호출 할 때 바이트 코드 의 상수 풀 뒤의 모든 요 소 를 분석 합 니 다.상수 탱크 에 이 어 2 개의 바이트 가 이러한 access 태그 입 니 다:ACCPUBLIC、ACC_FINAL 등;이후 2 개의 바 이 트 는 현재 클래스 이름 이 상수 탱크 에서 CONSTANTUtf8_Info 형식의 색인;이후 2 개의 바이트 가 아버지 클래스 의 이름 으로 상수 지 CONSTANTUtf8_Info 형식의 색인(색인 값 0 은 부모 클래스 를 null 로 표시 합 니 다.즉,Object 클래스 에서 직접 계승 합 니 다).그 다음 에 이 루어 진 인터페이스 수의 길이 와 대응 하 는 각 인터페이스 이름 은 상수 탱크 에서 CONSTANTUtf8_Info 형식의 색인 값;Field 와 Method 정의 정 보 를 잠시 건 너 뛰 고 클래스 의 attribute 표를 해석 합 니 다.attribute 배열 의 길 이 를 두 바이트 로 표현 합 니 다.각 attribute 항목 의 맨 앞 에 있 는 두 바이트 는 attribute 이름 입 니 다.SourceFile(sourceFile 값 읽 기),InnerClasses(시작 색인 을 일시 적 으로 기록),Enclosing Method(현재 익명 클래스 기록,로 컬 클래스 는 클래스 이름과 포 함 된 방법 명 과 설명자),Signature(클래스 의 서명 정보,범례 에 사용),Runtime VisibleAnnotations(일시 적 으로 시작 색인 기록),Deprecated(속성 표시),Synthetic(표지 속성),SourceDebugExtension(디 버 거 에 제공 하 는 사용자 정의 확장 정 보 를 문자열 로 읽 습 니 다),Runtime Invisible Annotations(시작 색인 을 일시 적 으로 기록 합 니 다)는 다른 인식 되 지 않 는 속성 에 대해 Attribute 체인 으로 기록 합 니 다.attribute 이름 이 accept 에서 attribute 배열 에서 지정 한 attribute 이름 에 부합 되면 들 어 오 는 attribute 배열 에 대응 하 는 항목 을 교체 합 니 다.분 석 된 정보 에 따라 다음 visit 방법 을 호출 합 니 다.

void visit(int version, int access, String name, String signature, String superName, String[] interfaces);
// sourceFile, sourceDebug
void visitSource(String source, String debug);
// EnclosingMethod attribute: enclosingOwner, enclosingName, enclosingDesc. 
// Note: only when the class has EnclosingMethod attribute, meaning the class is a local class or an anonymous class
void visitOuterClass(String owner, String name, String desc);
Runtime Visible Annotations 와 Runtime Invisible Annotations 속성 을 순서대로 분석 합 니 다.먼저 정 의 된 Annotation 의 설명자 와 실행 할 때 보 이 는 flag 를 분석 하고 사용자 정의 AnnotationVisitor 를 되 돌려 줍 니 다.

AnnotationVisitor visitAnnotation(String desc, boolean visible);
각 정 의 된 Annotation 에 대해 키 쌍 을 분석 하고 서로 다른 Annotation 필드 값 에 따라 Annotation Visitor 의 방법 을 호출 합 니 다.모든 해석 이 끝 난 후에 호출AnnotationVisitor.visitEnd방법:

public interface AnnotationVisitor {
 //         ,       ,visitArray           。
 void visit(String name, Object value);
 void visitEnum(String name, String desc, String value);
 AnnotationVisitor visitAnnotation(String name, String desc);
 AnnotationVisitor visitArray(String name);

 void visitEnd();
}
이전에 분 석 된 attribute 링크(표준 이 아 닌 Attribute 정의)는 모든 Attribute 인 스 턴 스 에 대해 ClassVisitor 의 visitAttribute 방법 을 호출 합 니 다.

void visitAttribute(Attribute attr);
Attribute 클래스 는 type 필드 와 바이트 배열 을 포함 합 니 다.

public class Attribute {
 public final String type;
 byte[] value;
 Attribute next;
}
모든 InnerClasses 속성 에 대해 ClassVisitor 의 visitInnerClass 방법 을 분석 하고 호출 합 니 다(이 속성 은 사실상 모든 직접 내부 클래스 와 그 자체 가 최상 위 클래스 로 저장 되 어 있 습 니 다).

void visitInnerClass(String name, String outerName, String innerName, int access);
분석 필드 는 인터페이스 배열 의 정의 에 따라 맨 앞 에 있 는 2 개의 바이트 가 필드 배열 의 길이 입 니 다.각 필드,앞 에 있 는 2 개의 바이트 가 방문 flag 로 정의 되 고 그 다음 에 2 개의 바이트 가 Name 색인 이 며 2 개의 바이트 의 설명자 색인 입 니 다.그 다음 에 Attribute 정 보 를 분석 합 니 다.ConstantValue,Signature,Deprecated,Synthetic,Runtime Visible Annotations,Runtime Invisible Annotations 및 표준 정의 되 지 않 은 Attribute 체인 을 사용 한 후 ClassVisitor 의 visitField 방법 을 호출 하여 FieldVisitor 인 스 턴 스 를 되 돌려 줍 니 다.

//   value          (      ,              ),        ,   null。
FieldVisitor visitField(int access, String name, String desc, String signature, Object value);
되 돌아 오 는 FieldVisitor 에 대해 서 는 Annotation 및 비 표준 Attribute 를 순서대로 분석 하고 visit 방법 을 호출 하 며 완 료 된 후에 visitEnd 방법 을 호출 합 니 다.

public interface FieldVisitor {
 AnnotationVisitor visitAnnotation(String desc, boolean visible);
 void visitAttribute(Attribute attr);
 void visitEnd();
}
분석 방법 은 필드 정의 에 따라 맨 앞 에 있 는 2 개의 바이트 가 방법 배열 의 길이 로 정 의 됩 니 다.각 방법 에 대해 앞의 2 개의 바이트 가 flag 에 접근 하 는 것 으로 정 의 된 다음 에 2 개의 바이트 가 Name 색인 이 고 2 개의 바이트 의 방법 설명자 색인 인 다음 에 Attribute 메 시 지 를 분석 합 니 다.Code,Exceptions,Signature,Deprecated,Runtime Visible Annotations,AnnotationDefault,Synthetic,Runtime Invisible Annotations,Runtime Visible ParameterAnnotations,Runtime Invisible ParameterAnnotations 및 비 표준 정의 Attribute 체인 이 있 습 니 다.Exceptions 속성 이 존재 하면 이상 클래스 그룹 을 분석 한 다음 에 ClassVisitor 의 visitMethod 방법 을 호출 하여 MethodVisitor 인 스 턴 스 를 되 돌려 줍 니 다.

MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions);
AnnotationDefault 는 Annotation 을 정의 할 때 기본 값 을 지정 합 니 다.그 다음 에 Runtime Visible Annotations,Runtime Invisible Annotations,Runtime Visible ParameterAnnotations,Runtime Invisible ParameterAnnotations 등 속성 을 순서대로 분석 하고 관련 AnnotationVisitor 의 visit 방법 을 호출 합 니 다.표준 이 아 닌 Attribute 체인 에 대해 MethodVisitor 의 visitAttribute 방법 을 순서대로 호출 합 니 다.

public interface MethodVisitor {
 AnnotationVisitor visitAnnotationDefault();
 AnnotationVisitor visitAnnotation(String desc, boolean visible);
 AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible);
 void visitAttribute(Attribute attr);
}
Code 속성 에 대한 분석,2 바이트 의 가장 깊 은 스 택 크기,최대 local 변수,code 점용 바이트 수 를 읽 고 MethodVisitorvisitCode()방법 으로 Code 속성 을 분석 하기 시 작 했 습 니 다.각 명령 에 대해 하나의 Label 인 스 턴 스 를 만 들 고 Label 배열 을 구성 합 니 다.Code 속성 중의 이상 표를 분석 하고 모든 이상 항목 에 대해 visitTry CatchBlock 방법 을 호출 합 니 다.

void visitTryCatchBlock(Label start, Label end, Label handler, String type);
라벨 은 다음 과 같은 정 보 를 포함 합 니 다:

/**
 * A label represents a position in the bytecode of a method. Labels are used
 * for jump, goto, and switch instructions, and for try catch blocks.
 * 
 * @author Eric Bruneton
 */
public class Label {
 public Object info;
 int status;
 int line;
 int position;
 private int referenceCount;
 private int[] srcAndRefPositions;
 int inputStackTop;
 int outputStackMax;
 Frame frame;
 Label successor;
 Edge successors;
 Label next;
}
Code 속성 중의 내부 속성 정 보 를 분석 합 니 다:LocalVariableTable,LocalVariableTypeTable,Line NumberTable,StackMapTable,StackMap 및 비 표준 정의 Attribute 체인 은 모든 Label 에 visitLine Number 방법 과 모든 Frame 에 visitFrame 방법 을 호출 하고 해당 하 는 명령 에 해당 하 는 방법 을 호출 합 니 다.

void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack);
// Visits a zero operand instruction.
void visitInsn(int opcode);
// Visits an instruction with a single int operand.
void visitIntInsn(int opcode, int operand);
// Visits a local variable instruction. A local variable instruction is an instruction that loads or stores the value of a local variable.
void visitVarInsn(int opcode, int var);
// Visits a type instruction. A type instruction is an instruction that takes the internal name of a class as parameter.
void visitTypeInsn(int opcode, String type);
// Visits a field instruction. A field instruction is an instruction that loads or stores the value of a field of an object.
void visitFieldInsn(int opcode, String owner, String name, String desc);
// Visits a method instruction. A method instruction is an instruction that invokes a method.
void visitMethodInsn(int opcode, String owner, String name, String desc);
// Visits a jump instruction. A jump instruction is an instruction that may jump to another instruction.
void visitJumpInsn(int opcode, Label label);
// Visits a label. A label designates the instruction that will be visited just after it.
void visitLabel(Label label);
// Visits a LDC instruction.
void visitLdcInsn(Object cst);
// Visits an IINC instruction.
void visitIincInsn(int var, int increment);
// Visits a TABLESWITCH instruction.
void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels);
// Visits a LOOKUPSWITCH instruction.
void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels);
// Visits a MULTIANEWARRAY instruction.
void visitMultiANewArrayInsn(String desc, int dims);
// Visits a try catch block.
void visitTryCatchBlock(Label start, Label end, Label handler, String type);
void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index);
// Visits a line number declaration.
void visitLineNumber(int line, Label start);
// Visits the maximum stack size and the maximum number of local variables of the method.
void visitMaxs(int maxStack, int maxLocals);
마지막 으로 ClassVisitor 의 visitEnd 방법 을 호출 합 니 다:

void visitEnd();
ClassWriter 구현
ClassWriter 는 ClassVisitor 인 터 페 이 스 를 계승 하여 해당 하 는 visit 방법 으로 동적 으로 바이트 코드 류 를 구성 할 수 있 습 니 다.다음 필드 정 보 를 포함 합 니 다:

public class ClassWriter implements ClassVisitor {
 //The class reader from which this class writer was constructed, if any.
 ClassReader cr;
 //Minor and major version numbers of the class to be generated.
 int version;
 //Index of the next item to be added in the constant pool.
 int index;
 //The constant pool of this class.
 final ByteVector pool;
 //The constant pool's hash table data.
 Item[] items;
 //The threshold of the constant pool's hash table.
 int threshold;
 //A reusable key used to look for items in the {@link #items} hash table.
 final Item key;
 //A reusable key used to look for items in the {@link #items} hash table.
 final Item key2;
 //A reusable key used to look for items in the {@link #items} hash table.
 final Item key3;
 //A type table used to temporarily store internal names that will not necessarily be stored in the constant pool. 
 Item[] typeTable;
 //Number of elements in the {@link #typeTable} array.
 private short typeCount;
 //The access flags of this class.
 private int access;
 //The constant pool item that contains the internal name of this class.
 private int name;
 //The internal name of this class.
 String thisName;
 //The constant pool item that contains the signature of this class.
 private int signature;
 //The constant pool item that contains the internal name of the super class of this class.
 private int superName;
 // Number of interfaces implemented or extended by this class or interface.
 private int interfaceCount;
 //The interfaces implemented or extended by this class or interface. 
 private int[] interfaces;
 //The index of the constant pool item that contains the name of the source file from which this class was compiled.
 private int sourceFile;
 //The SourceDebug attribute of this class.
 private ByteVector sourceDebug;
 //The constant pool item that contains the name of the enclosing class of this class.
 private int enclosingMethodOwner;
 //The constant pool item that contains the name and descriptor of the enclosing method of this class.
 private int enclosingMethod;
 //The runtime visible annotations of this class.
 private AnnotationWriter anns;
 //The runtime invisible annotations of this class.
 private AnnotationWriter ianns;
 //The non standard attributes of this class.
 private Attribute attrs;
 //The number of entries in the InnerClasses attribute.
 private int innerClassesCount;
 //The InnerClasses attribute.
 private ByteVector innerClasses;
 //The fields of this class. These fields are stored in a linked list of {@link FieldWriter} objects, linked to each other by their {@link FieldWriter#next} field. This field stores the first element of this list.
 FieldWriter firstField;
 //This field stores the last element of this list.
 FieldWriter lastField;
 //The methods of this class. These methods are stored in a linked list of {@link MethodWriter} objects, linked to each other by their {@link MethodWriter#next} field. This field stores the first element of this list.
 MethodWriter firstMethod;
 //This field stores the last element of this list.
 MethodWriter lastMethod;
 //true if the maximum stack size and number of local variables must be automatically computed.
 private final boolean computeMaxs;
 //true if the stack map frames must be recomputed from scratch.
 private final boolean computeFrames;
 //true if the stack map tables of this class are invalid. 
 boolean invalidFrames;
}
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 댓 글 을 남 겨 주 십시오.

좋은 웹페이지 즐겨찾기