最近也是研究Spring源码时发现Spring在对于注解的解析时使用的ASM来分析输入的Resource资源对象,分析其中的annotation元素,构造MetadataReader对象,并将annotation信息封装到AnnotationMetadata类型的annotationMetadata属性中,这引起了我对于ASM的好奇心。O(∩_∩)O哈哈~
- 什么是ASM
ASM是一个通用的字节码操作和分析的框架。它能够修改已经存在的class文件或者动态地以二进制流的形式生成字节码文件。它提供了通用的转换和分析算法,允许用户去组合自己自定义的复杂的转换工具和代码分析工具。ASM提供了像其他字节码操作框架相似的功能,但是ASM专注于简化它们的使用和执行,以为ASM的设计理念就是尽可能小巧,而且执行起来又不失速度,因此,ASM也受到了不少动态系统的青睐。
比如:AspectJ、BEA WebLogic、Oracle TopLink、BeanShell、Groovy、CGLIB等等。
- 初识ASM2.0
尽管ASM到目前为止,已经出到了5.0.2,但是我觉得ASM2.0还是比较适合入门学习的,他的功能基本都齐全,2.0~5.0大部分是对于部分内容的bug修复和性能调优,(ASM 3.x的确提供了不少新功能,所以现在ASM3.x使用的还是比较广泛的)。
java的字节码动态加载和反射功能使它成为了动态语言,尽管如此,java的反射在很多情况下也有时候会显得捉襟见肘,比如说很多开发者可能需要从非java源码中生成字节码,代表性的脚本语言像,Groovy(JSR-241)、BeanShell(JSR-274),或者是从元数据中获取信息生成字节码(比如,OR-mapping映射配置)。亦或当我们在处理存在的class文件或是java源码无法获得,一些工具需要去分析相互依赖 甚至是方法的行为去获得测试覆盖率、检测bug和反面模式。在JDK5 中,添加的新特性,注解和泛型,影响了字节码的结构,需要来自字节码操作工具特别关注来保持良好的运行表现。接下来让我们来认识一下小巧高速的字节码操作工具---ASM
ASM是java编写的使用visitor模式去生成java字节码文件、转换存在的class文件。它允许开发者避免直接处理类常量池和方法字节码的偏移量。和其他的字节码操作工具像javassist、BCEL或SERP等相比,ASM为开发者隐藏了字节码的复杂性,提供了较好的表现性能。
ASM的包结构如下图:
Core Package:核心包提供了读、写、转换java字节码的API,为其他包定义方法,核心包的功能足以生成java字节码,实现主要的字节码转换工作。
Tree Package:java 字节码的内存中的抽象。
Analysis Package:提供了基本的数据流分析以及树状结构中的方法的类型检查算法
Commons Package:ASM2.0添加的包,提供了几个通用的字节码转换方法和简化字节码生成的适配器
Util Package:包括几个帮助字节码和可以帮助开发和测试的简单的字节码校验
XML Package:提供了一个适配器可以让java字节码和xml文件相互转换,SAX适配器允许使用XSLT 去定义字节码转换。
接下来我们需要有一些对于JVM虚拟机规范定义的字节码结构的了解。Java类文件是8位字节的二进制流。数据项均是按照顺序紧密的排列开来,相邻的项之间没有间隔,这样的设计也使得class文件显得紧凑,而且比较节省存储存储空间。Java字节码文件中的数据项有大小不同许多项,由于每一项都有比较严格的定义,所有class文件能够比较顺利的从头到尾地解析。
[1]-------------------------------------------+
| Header and Constant Stack |
+--------------------------------------------+
| [*] Class Attributes |
[2]------------+------------------------------+
| [*] Fields | Field Name, Descriptor, etc |
| +------------------------------+
| | [*] Field Attributes |
[3]------------+------------------------------+
| [*] Methods | Method Name, Descriptor, etc |
| +------------------------------|
| | Method max stack and locals |
| |------------------------------|
| | [*] Method Code table |
| |------------------------------|
| | [*] Method Exception table |
| |------------------------------|
| | [*] Method Code Attributes |
| +------------------------------|
| | [*] Method Attributes |
+-------------+------------------------------+
上图简单描述了java字节码的结构。
所有的描述符,字符串字面量和其他常量在字节码文件的开头部分
每个类文件必须包含类名称、父类信息、接口信息等等以及常量池,其他一些可选元素,eg,字段列表、方法列表和所有的属性。
每个字段区包含字段信息(字段名称、访问标识、描述符和字段属性)
每个方法区包含相似的头信息以及用于校验字节码的栈信息和最大本地变量数目。对于非抽象、非本地方法包含一个方法指令表、一个异常表以及代码属性,除此以外还可以包含其他的方法属性
Class、Field、Method以及Method Code都有自己的名字,这些属性都表示关于字节码的各种各样的信息,比如说,源文件名称、内部类、签名(用于存储泛型信息)、行号、本地变量表、注解。JVM规范也允许定义自定义的属性,这些自定义属性会被标准VM忽略,但是可能需要包含附加信息
方法代码表包含了一系列java虚拟机指令
- 基于事件驱动字节码处理
对于ASM来说,java class文件被描述成一棵tree,使用visitor模式遍历整个字节码的二进制结构。基于事件驱动的处理方式让用户只需要关注于与编程有意义的部分,而不必理解java字节码的所有具体细节。
ASM的核心包使用了push模式去遍历复杂的字节码文件结构,ASM定义几个接口,比如ClassVisitor,FieldVisitor,MethodVisitor以及AnnotationVisitor。AnnotationVisitor是一个特殊的接口,允许我们表达继承关系的Annotation结构。接下来我们将来看看,这些接口是如何相互作用以及相互合作完成字节码文件的转换、获取字节码文件中的信息。
Core包可以逻辑上可以分成两个部分:
1.字节码生产者,比如ClassReader
2.字节码消费者,比如Writers(ClassWriter,FieldWriter,MethodWriter,and AnnotationWriter) adapters(ClassAdapter and MethodAdapter) 或者其他实现了Visitor接口的类。
ASM中的ClassReader可以直接通过字节数组或class文件间接的获得字节码数据,它能正确的分析构建字节码结构,并在内存中抽象出树状结构。ClassReader的accept方法接受一个实现了ClassVisitor接口的对象实例作为参数,然后依次调用ClassVisitor接口的各个方法。
字节码空间上的偏移量被转换成visit事件(对不同visit方法的调用)时间上调用的先后,这个过程用户是无法进行干预的,我们可以做的是通过提供不同的Visitor来对字节码树进行修改。ClassReader的内部顺序访问时有一定要求的,但是我们也可以抛开ClassReader手动的执行这一过程,只要我们调用visit的顺序正确。但是这也无疑在获取最大化的灵活度的同时增加了字节码修改的复杂度。
ClassVisitor通过责任链模式,可以简单地封装对于字节码文件的各种修改,将字节码的字节便宜对开发者透明化,我们只需override相应的visit方法即可。ClassAdapter实现了ClassVisitor接口定义的所有方法,实例化一个ClassAdapter需要传入一个实现了ClassVisitor接口的对象实例,对ClassAdapter中的方法的调用其实都委托给了这个作为参数传入的实现ClassVisitor接口的对象实例。然后依次传递下去形成责任链。所以当我需要修改一个字节码文件时,只需从ClassVisitor派生一个子类即可。这个责任链最终可以以ClassWriter结束,生成我们需要的处理过的字节码文件。eg:
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor cc = new CheckClassAdapter(cw); ClassVisitor tv = new TraceClassVisitor(cc, new PrintWriter(System.out)); ClassVisitor cv = new TransformingClassAdapter(tv); ClassReader cr = new ClassReader(bytecode); cr.accept(cv, ClassReader.SKIP_DEBUG); byte[] newBytecode = cw.toByteArray();
相关推荐
Oracle ASM 元数据是Oracle ASM用来控制磁盘组并且元数据驻留在磁盘组中的信息
ASM是一个开源的Java字节码操控和分析框架,它可以直接用来生成和修改Java类文件,是Java动态代理和字节码增强技术的重要工具。在深入学习Java字节码和ASM之前,我们需要先理解Java编译和运行的基本过程。 1. **...
汇编语言ASM从入门到精通普通下载汇编语言ASM从入门到精通普通下载
汇编语言(ASM)从入门到精通,适合汇编语言初学者学习使用。
汇编语言(ASM)从入门到精通. 新手看最好
汇编语言(ASM)从入门到精通。。。不错的东东
对初学者而言,汇编的许多命令太复杂,往往学习很长时间也写不出一个漂漂亮亮的程序,以致妨碍了我们学习汇编的兴趣,不少人就此放弃。
### AT&T ASM汇编语言入门教程 #### 一、引言 在《从零开始编程》这本书中,作者乔纳森·巴特莱特(Jonathan Bartlett)与编辑多米尼克·布鲁诺(Dominick Bruno Jr.)为读者提供了一个深入了解计算机底层原理以及...
汇编语言(ASM)从入门到精通。很好的书籍!!!!!!!!!!
综上所述,"asm汇编入门"的主题涵盖了汇编语言的基础知识和应用,而NLC阅读器则可能涉及自然语言处理技术在编程中的应用。这两个知识点虽然属于不同的层次,但都体现了计算机科学中从低级到高级,从机器到人的交互...
( 黑基ASM汇编语言入门(一)VIP专题讲座.pps )
《汇编语言(ASM)从入门到精通》是一份针对汇编语言学习者的全面参考资料,旨在帮助初学者迅速掌握汇编基础知识并逐步精通高级技巧。汇编语言是计算机科学的基础,它是一种低级编程语言,直接对应于机器指令,因此...
ASM汇编语言全集是一份宝贵的资源,涵盖了汇编语言的各个方面,对于学习和深入理解计算机底层原理极其有用。汇编语言是计算机编程的一种低级语言,它与机器语言紧密相关,每一行汇编指令几乎都能直接转换为特定的...
汇编语言(Asm)从入门到精通 chm版 经典之作
高手总结的汇编语言(ASM)从入门到精通,很好的入门资料,讲的很容易理解
7. **工具的使用**:压缩包中的"dais使用入门怎样生成hex 文件.exe"可能是一个简易的ASM转HEX工具。使用这类工具通常需要指定ASM源文件,工具会自动完成汇编和转换过程,生成HEX文件。用户应根据软件的说明文档进行...