ASM(四) - ASM定类、方法、属性

下面三篇文章讲解怎么定义类、方法、变量等说的很详细 明了。

 

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还提供了MethodVisitorFieldVisitorAnnotationVisitor对方法,字段和注解操作。 

 

三、 Tree API

      Tree API是基于对象的方式来处理字节码,Tree API的最核心的一个类就是ClassNode它就代表了一个Java Class文件,它里面的属性对应到了一个Class文件的各个部分。

 

ClassNode,用来创建一个继承了java.lang.Runnable接口的接口ASMInterface,它包含了一个方法public void stop(),最后将生成的字节码通过ClassWriter输出到文件。

和创建类一样,通过Tree API修改一个类也只需要修改ClassNode的属性。如果你要修改方法,字段或者注解,那么可以通过ClassNode拿到MethodNodeFieldNodeAnnotationNode来进行对应的修改。

 

四、什么时候使用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/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值