ASM是什么?
借用别人的话 :ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。
ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为(通过实现ClassFileTransformer接口)。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。 与 BCEL 和 SERL 不同,ASM 提供了更为现代的编程模型。对于 ASM 来说,Java class 被描述为一棵树;使用 “Visitor” 模式遍历整个二进制结构;事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分,而不必了解 Java 类文件格式的所有细节:ASM 框架提供了默认的 “response taker”处理这一切。
第一章 介绍
1.1动机
程序分析、生成和转换是非常有用的技术,它具有以下的应用场景:
l 程序分析(包括从简单的综合性分析到一个全面的语义分析)可以被用来寻找潜在的bug,发现未使用的代码,进行工程代码的逆向。
l 程序生成被用在编译器当中。这包括传统的编译器,也包括为分布式编程使用的stub或skeleton 编译器,即时编译器等
l 程序转换可以被用来优化或者混淆程序,为程序插入debugging或者性能检测代码,方便面向对象编程等。
所有这些技术可以被用到任意的编程语言,但是难易程度依赖于具体语言。对于Java来说,这些技术可以被用在Java源代码或者编译后的Java类。对于编译好的类,有一个明显的好就是不需要源代码。因此,程序转换可以被用在任何应用上,包括闭源软件以及商业软件。另一个好处是:在程序被加载之JVM之前,使得在运行时分析、产生或者转换类变为可能。这个好处使得stub编译器或者aspect weaver之类的工具对用户透明。
考虑到程序分析、产生和转化的诸多用处,许多工具已经实现了这些功能。ASM就是这些工具中的一个,它面向Java语言,为运行时(也支持脱机)类的产生和转换设计。因此,ASM的库被设计针对编译后的java类工作。ASM被尽量的设计的占用内存小以及执行速度快。此处省略两句废话。
ASM不仅仅一个可以产生和转化编译后Java类的工具同时它也是最新的和最高效的。以下省略7条优点。
1.2综述
1.2.1范围
ASM的目标是产生、转换和分析表示为字节数组的编译后的Java类,因此ASM提供工具通过使用更高层的概念来读写和转换这些字节数组,比如:数字常量、字符串、Java识别符、Java类型、Java类结构元素等。注意,ASM类库的范围严格的限制为读写、转换和分析类。类的加载过程不在这个范围内。
1.2.2模型
ASM提供两种API,第一种是core API,提供一种基于事件的类的代表,另一种是tree API,提供了一种面向对象的代表。
基于事件的模型中一个类用一系列事件代表,其中每个事件代表一个类的元素,比如说头、域、方法的声明、说明等。基于事件的API定义了可能的事件的集合以及他们发生的顺序,并且提供了一个类的分析器来为每个分析过的元素产生一个事件,就像一个类的writer为这些事件序列产生编译好的类。
基于对象的模型使用一个对象树来代表一个模型,每个对象代表类的的一部分,比如类本身,一个域,一个方法,一个说明等。每个对象都有一个到委托对象的索引。基于对象的API提供了一种将一系列事件代表的类转化为对象树代表的同一个类的方法,反之亦然。换句话说,基于对象的API是建立在基于事件的API之上的。
这两个API可以类比为XML的Simple API和DOM API,基于事件的API类似与Simple API,基于对象的API类似于DOM。
ASM提供两种API的原因是:没有最好的API,每一种API都有其优劣之处。
l 基于事件的API比较快速、相比基于对象的对内存的需求比较小,因为需要内存来创建和存储代表类的对象树。
l 基于事件的API很难实现类的转换,因为仅有一个类元素在某个给定时间可用,而基于对象的API是内存中的整个类可用。
注意:两个API在同一时刻只管理一个类,如果发生冲突,则由用户来修改。
1.2.3体系结构
ASM拥有健壮的体系结构。实际上,基于事件的API围绕事件生产者、消费者和许多事先定义的事件过滤器、用户定义的生产者、消费者和过滤器可以被添加。因此,使用这个API分为两步:
l 将事件生产者、过滤器和消费者组建组装成一个可能的复杂体系结构。
l 接着启动事件生产者来运行生成或者转换的过程。
基于对象的API也用于一个完整的体系结构:实际上,操作一棵树的类的生产或者转换组件可以进行合成,他们之间的链接代表了转换的顺序。
尽管在典型的ASM中基于组件的体系结构是非常简单的,但是我们可以想象一个复杂的体系如下图,其中箭头代表分析器、读写器或者转换器之间的基于时间或者基于对象的交流,链中表示了所有的转换可能。
1.3组织
ASM的类库被组织在不同的包中,这些包分布在许多jar包中:
l org.objectweb.asm和org.objectweb.asm.signature包定义了基于事件的API,并且提供了类分析器和读写器组件。他们包含在asm.jar中。
l org.objectweb.asm.util在asm-util.jar包中,提供了许多基于core API(基于事件)的工具,这些工具可以在开发和debug ASM应用的时候使用。
l org.objectweb.asm.commons提供了许多有用的预先定义的类转换组件,其中大多数是基于core API。它包含在asm-common.jar中。
l org.objectweb.asm.tree package定义了基于对象的API,并且提供了基于事件和基于对象之间的转换工具。它包含在asm-tree.jar中。
l org.objectweb.asm.tree.analysis提供一个类分析框架和许多预先定义的类分析器,基于树的API。它包含在asm-analysis.jar中。
文档包含两个部分。第一部分涵盖了 core API以及asm, asm-util和asm-commons包。第二部分涵盖了树API以及asm-tree和asm-analysis。每个部分至少包含一个与类相关的API章节、一个与方法相关的API章节以及一个和注释、类的类型相关的API章节。每个章节涵盖了编程接口、相关工具以及预先定义好的组件。所以例子的源代码可以在ASM网站上找到。
这样的组织使得一步步介绍类文件的特点变得简单,但是有时还会需要将一个简单的ASM类分散到许多部分。因此,我们推荐按照文档的顺序来阅读这份文档。