第一章:ASM介绍
1.1 ASM动机:
程序的分析,生成,转换技术可以应用到许多场景:
1.程序分析,从简单的语法解析到完整的语义分析,可以应用在程序中找到潜在的bug,发现无用的代码,工程代码的逆向等等。
2.代码生成应用在各种编译器中:既包括传统的编译器也包括分布式编程的stub或者skeleton编译器,即时编译器等等。
3. 代码转换,可用于优化或混淆程序,向应用中插入测试或性能监控程序,面向切面编程等等。
这些技术可以用在任何编程语言,但或多或少容易依赖语言。在java 语言中,它们可以应用在源码中也可以应用在编译后的class文件中。用在编译后的class文件中的好处之一是:显然,不需要源代码。代码转换可以应用到任意的应用,包括源码封闭的应用和商业应用中。另外一个应用到编译后的代码是:可以在运行时期(即在类被加载到java虚拟机之前)来分析,产生,转换类。java虚拟机用来在运行时期产生、编译源代码,但它比较慢并且要求有一个完整的java编译器。好处是:对用户来说,这类工具例如stub编译器或者切面编织器是透明的。
由于程序分析,产生和转换技术有如此多种用途,很多种语言包含java的分析、生成和转换的工具已经被开发出来了。ASM就是一种专为java语言设计的在运行时期(不是离线)的类产生、转换的工具。因此ASM库专为编译后的java类文件。它设计的尽可能的运行快,占用空间少。尽可能的快是为了尽可能不影响在运行期使用ASM应用的速度;尽可能的小是为了用在内存资源受到严格限制的环境避免因为使用ASM而造成小应用或者库的空间膨胀。
ASM不仅仅是一个产生、转换编译后的java类的工具,它同时也是一种最现代最有效率的工具。可以从http://asm.objectweb.org下载到ASM. ASM的主要特点有以下几点:
1. 它有一个简单易用的、完美设计的、模块化的API.
2. 它文档完善并有一个Eclipse关联的插件。
3. 它提供对java 最新版本java 7的支持。
4. 体积小,速度快,健壮性好。
5. 对新用户提供庞大的社区支持。
6. 开源,允许你任意使用。
1.2 ASM 概述:
1. 域
ASM库的目标是为了产生、转换、分析编译后的JAVA 类(表现为字节数组,因为它们存储在磁盘上然后被加载到java 虚拟机中)。正因为有此目标,ASM提供了对这些字节数组读写和转换的工具,这些工具使用比字节更高级别的抽象如数字常量,字符串,java标识符,java 类型,java类结构元素等进行读写和转换。注意:ASM库的域被严格限定在对类的读写,转换和分析。特别是类的加载时超过这个域的。
2. 模型
ASM库提供两种类型的API来产生,转换编译后的类:核心API提供基于事件的类的展现;树API提供了一个基于对象的展现。
基于事件的模型中,一个类表现为一个事件序列,每个时间代表了类的一个元素,例如header、field、method声明、一条指令等。基于事件的API定义了的一组可能事件和必须发生的顺序,并提供了一个类解析器:它根据它解析的每一个元素产生一个事件;一个写入器:从事件序列中产生编译后的类。
基于对象的模型中,一个类表现为一个对象树,每个对象代码了类的一部分,例如:类本身,一个field,一个方法,一条指令等。每个对象具有代表其组成的对象引用。基于对象的API提供了将代表一个类的事件序列转换成代表同一个类的对象树的方法,反之亦然,将一个对象树转换为等同的事件序列。换句话说,基于对象的API 建立在基于事件的API之上。这个两个API的对比可以形容为:SAX(xml简单api)和DOM(文档对象模型),其中基于事件的API类似于SAX,基于对象的API类似于DOM。基于对象的API建立在基于事件的API之上,正如DOM建立在SAX上一样。
ASM提供了这两种API,因为没有一种API 能比另外一种API更好。事实上,每个API都有自己的优缺点:
1、基于事件的API比基于对象的API的速度更快,需要的空间更少。因为不需要再内存中创建和存储一个代表类的对象树(同样的情况也存在于SAX和DOM之间)。
2、 基于事件的API更难于实现类的转换,因为在任意时间只能访问到类的一个元素(对应当前时间的元素),而基于对象的API都可以在内存中访问到。
注意:两种API只能在一个事件管理一个类,并且各自独立。类的继承信息没有保存,若一个类的转换影响到别的类,必须由用户去修改那些类。
3. 架构:
ASM 应用有很强的架构视图。事实上,基于事件的API围绕事件生成者(类解析器)、事件消费者(类写入器)和各种预定义的过滤器进行组织,用户定义的生产者、消费者和各种过滤器可以很容易添加上去。因而使用此API需要两步:
1、将事件的生产者、过滤器、消费者组件汇编成复杂的架构。
2、然后运行事件生产者来运行产生或者转换进程。
基于对象的API同样有一个架构视图:由操作对象树的类产生器和转换器组件构成,两者的连接表示转换的顺序。
尽管大部分组件架构特别是ASM应用是非常简单的,但也能够联想到复杂的架构,如下:
箭头代表类解析器、写入器、转换器之间基于事件或者基于对象的连接,在链型结构中到处存在基于事件或者对象的转换。
1.3 组织结构:
ASM库有几个不同的包组成,它们被放入到不同的jar文件中:
包org.objectweb.asm 和org.objectweb.asm.signature定义了基于事件的API,并且提供了类解析器和写入器组件,它们被打入到asm.jar文件中。
包org.objectweb.asm.util,被打入到asm-util.jar文件中,提供了许多基于核心API的工具,这些工具可以用在ASM应用的开发和调试当中。
包org.objectweb.asm.commons提供了一些有用的预定义类转换器,大部分基于核心API。它被打包到asm-commons.jar。
包org.objectweb.asm.tree,打包到asm-tree.jar文件中,定义了基于对象的API,提供了基于事件和基于对象的表现形式的转换工具。
包org.objectweb.asm.tree.analysis提供了基于树API的一个类分析框架和一些类分析器,打包到asm-analysis.jar文件。
该文档包含两个部分,第一部分介绍了核心API,例如:asm,asm-util和asm-commons文件。第二部分介绍了树API,例如:asm-tree和asm-analysis文件。每部分至少有一章介绍关联类的API,一章关联方法的API,一章关联注解、通用类型等的API。每章包含编程接口和相关工具及预定义组件。所有的实例源码均可在ASM官方网站下载。
这种组织形式可以更容易地逐步引入类文件的各种特征,但有时需要在部分章节中扩展单个ASM类的表现形式。因此,建议按照文档的顺序安排来读取。如果仅使用该手册文档的ASM API,请使用Javadoc
排版约定
<略>
致谢
感谢François Horn。在编纂这篇文档期间,他的有价值的评论大大提高了该文档的结构和可读性。
核心API、TREE API后续中。。。。