动机

程序分析,生成和转换是有用的技术,可以在许多情况下使用:

程序分析

范围从简单的语法分析到完整的语义分析,可用于查找应用程序中的潜在错误,检测未使用的代码,反向工程代码等。

在编译器中使用程序生成。

其中包括传统的编译器,还有用于分布式编程的存根或骨架编译器,即时编译器等

程序转换可用于优化或混淆程序,

将调试或性能监控代码插入应用程序,用于面向方面的编程等

所有这些技术都可以用于任何编程语言,但这或多或少容易实现,具体取决于语言。

对于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也具有体系结构方面:

确实可以构成对对象树进行操作的类生成器或转换器组件,它们之间的链接表示转换的顺序。

image

组织信息

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 字节码  

参考文档

https://asm.ow2.io/asm4-guide.pdf