动机
程序分析,生成和转换是有用的技术,可以在许多情况下使用:
程序分析
范围从简单的语法分析到完整的语义分析,可用于查找应用程序中的潜在错误,检测未使用的代码,反向工程代码等。
在编译器中使用程序生成。
其中包括传统的编译器,还有用于分布式编程的存根或骨架编译器,即时编译器等
程序转换可用于优化或混淆程序,
将调试或性能监控代码插入应用程序,用于面向方面的编程等
所有这些技术都可以用于任何编程语言,但这或多或少容易实现,具体取决于语言。
对于Java,它们可以在Java源代码或已编译的Java类上使用。
处理已编译类的优点之一是,显然,不需要源代码。
因此,程序转换可用于任何应用程序,包括封闭源代码和商业应用程序。
处理已编译代码的另一个优点是,可以在将类加载到Java虚拟机中之前在运行时分析,生成或转换类(可以在运行时生成和编译源代码,但这确实很慢,并且需要完整的Java编译器)。
优点是存根编译器(stub compilers)或Aspect Weaver等工具对用户透明。
由于程序分析,生成和转换技术的许多可能用法,因此已经为许多语言(包括Java)实现了许多用于分析,生成和转换程序的工具。
ASM 的作用
ASM是Java语言的其中一种工具,旨在用于运行时(但也可以脱机)类生成和转换。
因此,ASM库被设计为在编译的Java类上工作。
尽可能的小
它还被设计为尽可能快和尽可能小。
为了不减慢速度,尽可能快是很重要的在运行时使用ASM进行动态类生成或转换的应用程序过多。
为了在内存受限的环境中使用,并避免过大的膨胀,尽可能地小非常重要。
使用ASM的小型应用程序或库的大小。
其他作用
ASM不是生成和转换已编译Java的唯一工具类,但是它是最新且有效的类之一。
可以下载来自http://asm.objectweb.org。
其主要优点如下:
它具有简单易用,设计良好的模块化API。
- 有据可查,并且具有关联的Eclipse插件。
- 它支持最新的Java版本Java 7。
- 它体积小,速度快并且非常坚固。
- 其庞大的用户社区可以为新用户提供支持。
- 其开源许可证允许您以几乎任何所需的方式使用它。
概览
Scope
ASM库的目标是生成,转换和分析以字节数组表示的已编译Java类(因为它们存储在磁盘上并已加载到Java虚拟机中)。
为此,ASM提供了使用比字节更高的概念来读取,写入和转换此类字节数组的工具,例如数字常量,字符串,Java标识符,Java类型,Java类
结构元素等
请注意,ASM库的范围严格限于读取,编写,转换和分析类。
特别是,类加载过程超出了范围。
Model
ASM库提供了两个用于生成和转换已编译类的API:
核心API提供基于事件的类表示,而树API提供基于对象的表示。
在基于事件的模型中,一个类由一系列事件表示,每个事件代表该类的元素,例如其标题,字段,方法声明,指令等。
基于事件的API定义了可能的事件集以及它们必须发生的顺序,并提供了一个类解析器,该类解析器为每个被解析的元素生成一个事件,以及一个类编写器,从这些事件的序列中生成已编译的类。
在基于对象的模型中,用对象树表示一个类,每个对象代表该类的一部分,例如类本身,字段,方法,指令等,每个对象都具有对这些对象的引用。 代表其成分。
基于对象的API提供了一种将表示类的事件序列转换为表示对象的对象树的方法。
相同的类,反之亦然,将对象树转换为等效的事件序列。
换句话说,基于对象的API建立在事件之上基于API。
二者的关系
这两个API可以与XML文档的简单API(SAX)和文档对象模型(DOM)API进行比较:
基于事件的API与SAX相似,而基于对象的API与DOM类似。
基于对象的API建立在基于事件的API之上,就像可以在SAX之上提供DOM一样。
ASM提供这两种API,因为没有最佳的API。
优缺点
实际上,每个API都有自己的优点和缺点:
与基于对象的API相比,基于事件的API更快,并且所需的内存更少,因为不需要创建并在内存中存储代表该类的对象树(SAX和DOM之间也存在相同的区别)。
但是,使用基于事件的API来实现类转换可能会更加困难,因为在任何给定时间只有该类的一个元素(与当前事件相对应的元素)才可用,而整个类都可以在基于对象的内存中使用 API。
请注意,这两个API一次仅管理一个类,而与其他API无关:
不维护有关类层次结构的信息,并且如果类转换影响其他类,则由用户决定是否修改这些其他类。
Architecture
ASM应用程序具有强大的体系结构方面。
实际上,基于事件的API是围绕事件生成器(类解析器),事件使用者(类编写器)和各种预定义的事件过滤器组织的,可以向其中添加用户定义的生产者,使用者和过滤器。
因此,使用此API分为两个步骤:
(1)将事件产生器,过滤器和使用者组件组装成可能复杂的架构,
(2)然后启动事件生产者以运行生成或转换过程。
基于对象的API也具有体系结构方面:
确实可以构成对对象树进行操作的类生成器或转换器组件,它们之间的链接表示转换的顺序。
组织信息
ASM库组织在几个软件包中,这些软件包分布在多个jar文件:
- org.objectweb.asm和org.objectweb.asm.signature
包定义基于事件的API,并提供类解析器和编写器组件。
它们包含在asm.jar存档中。
asm-util.jar存档中的org.objectweb.asm.util包,提供了基于核心API的各种工具,这些工具可以在ASM应用程序的开发和调试。
- org.objectweb.asm.commons
包提供了几个有用的预定义类转换器,主要基于核心API。
它包含在asm-commons.jar存档中。
- asm-tree.jar
存档中的org.objectweb.asm.tree包,定义基于对象的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类的表示形式分散在几个部分中。
因此,建议按顺序阅读本文档。
整体时序图
AOP 技术对比
AOP 底层技术 | 功能 | 性能 | 面向接口编程 | 编程难度 |
直接改写 class 文件 | 完全控制类 | 无明显性能代价 | 不要求 高,要求对 class 文件结构和 Java 字节码有深刻了解 | |
JDK Instrument | 完全控制类 | 无论是否改写,每个类装入时都要执行 hook | 程序 不要求 高,要求对 class 文件结构和 Java 字节码有深刻了解 | |
JDK Proxy | 只能改写 method | 反射引入性能代价 | 要求 低 | |
ASM | 几乎能完全控制类 | 无明显性能代价 | 不要求 中,能操纵需要改写部分的 Java 字节码 |