面试题Android开发经验谈首页投稿(暂停使用,暂停投稿)

ASM简介(一)

2016-07-28  本文已影响741人  千里山南

之前简单研究过ASM这个字节码修改框架,最近要用到,故简单复习下。顺便翻译下官方文档(翻译主要是给自己看的,因此比较随意,自己看一眼就明白的直接跳过了,大家权且当作是读书笔记吧)。

字节码修改的必要性

ASM的优势

概览

ASM设计用于字节码的改写、生成。其有两套API一套基于访问者模式、一套基于树的数据结构。基于访问者模式的api,类中的每个数据结构都是一个Event,类的生成同样基于这样的Event。基于树的数据结构的api是面向对象的一种设计,类被表示为一个对象。这两套api的区别类似xml解析中的SAX和DOM。两套api都是对同一个class操作的,如果用户需要修改相关联的类需要自己手动管理。

功能介绍

asm.jar 包含时间模式的API,适用于class文件的读写。
asm-util.jar 包含一些工具类,基于base api 用于协助开发调试
asm-commons.jar 提供了一些很有用的预定义基于事件的类转换器
asm-tree.jar 提供了基于对象的api并提供两种api的转化
asm-analysis.jar 提供了基于对象api的类的分析框架类

字节码文件格式概览

类源码和字节码区别:每个class文件只包含一个类,没有注释。没有package 和 import部分,所有的类型必须使用全名。另一个重要的区别在于,编译后的字节码有一个常量存放区。存放着类中出现的所有的数字、字符串、类型常量。这些常量只被定义一次,被类的其他部分通过索引引用。不过使用ASM的话常量定义区对我们而言是透明的。另一个区别在于源文件和class文件中对类型的引用方式不同。
class 文件的结构如下

Modifiers, name, super class, interfaces
Constant pool: numeric, string and type constants
Source file name (optional)
Enclosing class reference
Annotation*
Attribute*
Inner class* Name
Field* Modifiers, name, type
Annotation*
Attribute*
Method* Modifiers, name, return and parameter types
Annotation*
Attribute*
Compiled code

bytecode中type表示如下:类似jni接口

Java type Type descriptor
boolean Z
char C
byte B
short S
int I
float F
long J
double D
Object Ljava/lang/Object;
int[] [I
Object[][] [[Ljava/lang/Object;

方法描述也类似jni

Method declaration in source file Method descriptor
void m(int i, float f) (IF)V
int m(Object o) (Ljava/lang/Object;)I
int[] m(int i, String s) (ILjava/lang/String;)[I
Object m(int[] i) ([I)Ljava/lang/Object;

接口和组件

class的生成和转换时基于ClassVisitor抽象类的。该类的每个方法都对应class的一个结构。简单的结构对应的方法入参为结构的描述,方法返回void即可。复杂的使用一个init方法来访问,并且返回一个描述改结构的visitor类。例如visitAnnotation、visitField\visitMethod需要返回AnnotationVisitor、FieldVisitor、MethodVisitor。这样整个结构可以被递归的调用

public abstract class ClassVisitor { 
    public ClassVisitor(int api); 
    public ClassVisitor(int api, ClassVisitor cv); 
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces); 
            public void visitSource(String source, String debug); 
            public void visitOuterClass(String owner, String name, String desc); 
    AnnotationVisitor visitAnnotation(String desc, boolean visible); 
    public void visitAttribute(Attribute attr); 
    public void visitInnerClass(String name, String outerName, String innerName, int access); 
    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value); 
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions); 
    void visitEnd(); 
}

ClassVisitor方法调用必须要按照以下顺序:visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )* ( visitInnerClass | visitField | visitMethod )* visitEnd

基于ClassVisitor ASM提供了 ClassReader来解析字节流格式的class. ClassWriter 用于生成二进制格式的class. ClassVisitor 可以看作是Event的过滤器

上一篇 下一篇

猜你喜欢

热点阅读