下面三篇文章讲解怎么定义类、方法、变量等说的很详细 明了。
http://alvinqq.iteye.com/blog/940960
http://alvinqq.iteye.com/blog/940965
http://alvinqq.iteye.com/blog/940970
一、如何使用ASM
ASM提供了两套API供使用者使用,一套叫Core API,是基于事件的方式对字节码进行处理;另一套叫Tree API,是基于对象的方式对字节码进行处理。如果你熟悉XML解析,那么实际上Core API就是SAX这种处理模式,而Tree API就是DOM这种处理模式。

二、Core API
使用Core API进行对字节码进行处理一般需要三个部分:
- 一个事件的生产者,用于产生各种事件,通常这会是一个
ClassReader - 一个事件的消费者,用于消费各种事件,通常这会是一个
ClassWriter - 若干个事件的过滤器,这些过滤器可以对感兴趣的事件进行过滤来处理,这通常会是一些
ClassVisitor
其处理过程如下图所示:
从文件流中读入一个待处理的Class文件,然后new了ClassReader,作为事件源,然后new了一个ClassWriter,作为事件的接收者,还实现了一个ClassVisitor,这个ClassVisitor将所有的public方法变成了private的方法。接着通过调用cr.accept方法来触发事件,通过cw.toByteArray来拿到处理后的字节码并且输出到文件。
从前面的图可以看出,采用Core API处理字节码,其实就是通过继承ClassVisitor,并且覆盖ClassVisitor中的对应的方法来对特定的事件进行处理的过程,其实这里的事件基本上对应到了Class文件中的各个部分,除了常量池部分,所以如果了解了Class文件的结构,那么用Core API处理起来应该得心应手。
除了ClassVisitor之外,Core API还提供了MethodVisitor、FieldVisitor、AnnotationVisitor来对方法,字段和注解操作。
三、 Tree API
Tree API是基于对象的方式来处理字节码,Tree API的最核心的一个类就是ClassNode,它就代表了一个Java Class文件,它里面的属性对应到了一个Class文件的各个部分。
ClassNode,用来创建一个继承了java.lang.Runnable接口的接口ASMInterface,它包含了一个方法public void stop(),最后将生成的字节码通过ClassWriter输出到文件。
和创建类一样,通过Tree API修改一个类也只需要修改ClassNode的属性。如果你要修改方法,字段或者注解,那么可以通过ClassNode拿到MethodNode、FieldNode、AnnotationNode来进行对应的修改。
四、什么时候使用Core API,什么时候使用Tree API?
Core API和Tree API其实各有优缺点:
- Core API的优势是处理速度快,占用内存小,因为它不需要在内存中将整个Class文件表示出来,缺点是基于事件的方式处理,如果错过一个事件,那么就是过了这个村,没有这个店了,这样如果需要实现诸如将特定
GOTO出插入其他指令,就会比较麻烦,因为GOTO可以跳转到之前的指令,但是之前的指令的事件已经被处理了,到时候只能再次触发一遍事件来处理。 - Tree API的优势就是Core API的劣势,对于上面提到的
GOTO的这种情况,Tree API处理起来就轻松了很多,因为在内存中有Class文件的完整表示,随便什么样的顺序去改都是没有问题的。缺点就是占用内存比较大,处理速度比较慢。
如果你查看ClassNode的源代码,那么可以发现ClassNode事实上继承了ClassVisitor。那么,我们就可以将在实际操作的时候将Core API和Tree API结合起来,灵活运用各自的优缺点去解决问题。
五、辅助工具类
ASM除了提供了Core API和Tree API两套API以外,还提供了几个比较实用的工具类
CheckClassAdapter
实际上,用ASM生成的字节码可能并不符合Java虚拟机规范的,如果需要检查生成的字节码符不符合规范,那么可以用CheckClassAdapter作为一个ClassVisitor加入到ClassVisitor链中,如果字节码不符合规范,那么CheckClassAdapter就会抛出异常。
ASMifier
ASM作为一个字节码操作工具,相对于其他的字节码操作工具,比如Javassist,写起来还是比较烦琐的,如果你已经有了一个Class文件,想要知道如何通过ASM生成这个Class文件,那么就可以直接用ASMifier这个类,通过这个类,可以直接生成出生成目标类的ASM代码,一定程度上简化了直接手写ASM代码的繁琐工作。
ASMifier可以直接通过命令行来使用,比如那我们刚才生成的那个ASMInterface为例:

可以看到ASMifier直接将生成ASMInterface所需要的ASM代码直接打印出来了。
LocalVariableSorter
假设你要往一个方法里面加入一个本地变量,那么你就需要将这个变量加入到本地变量表的最后,遗憾的是,本地变量表的大小只有当你在调用visitMaxs的时候才知道,通常,这个时候已经到了方法的结尾处,再想加本地变量已经晚了,现在通过LocalVariableSorter这个ClassVisitor,你就可以非常简单插入一个本地变量。
转载:http://www.khotyn.com/2012/03/06/asm_note/
深入理解ASM字节码操作技术:CoreAPI与TreeAPI
本文详细介绍了ASM字节码操作技术中的CoreAPI和TreeAPI,包括它们的工作原理、使用场景及优缺点。通过实例展示了如何使用这两种API对Java类进行操作,并提供了几个实用的辅助工具类,如CheckClassAdapter、ASMifier和LocalVariableSorter,以简化字节码操作流程。
700

被折叠的 条评论
为什么被折叠?



