读书人

ASM指南通译-5

发布时间: 2012-12-25 16:18:28 作者: rapoo

ASM指南翻译-5

2.2.4转换类


图2.7

?

可以通过修改visit方法的其它参数来实现其它转换,而不仅仅是修改类的版本号。例如,你可以给类增加一个借口。当然也可以修改类的名称,但是这需要修改很多东西,而不只是修改visit方法中类的名称。实际上,类名可能在很多地方存在,所有这些出现的地方都需要修改。

?

优化

前面的转换只改变了原始类中的四个字节。尽管如此,通过上面的代码,b1被完整的解析,产生的事件被用来从头构造b2,尽管这样做不高效。另一种高效的方式是直接复制不需要转换的部分到b2,这样就不需要解析这部分同时也不产生对应的事件。ASM会自动地对下面的方法进行优化:

?

如果ClassReader检测到一个MethodVisitor直接被ClassVisitor返回,而这个ClassVisitor(如ClassWriter)是通过accept的参数直接传递给ClassReader,这就意味着这个方法的内容将不会被转换,并且对应用程序也是不可见的。在上面的情形中,ClassReader组件不会解析这个方法的内容,也不会产生对应的事件,而只是在ClassWriter中复制该方法的字节数组。

?

这个优化由ClassReader和ClassWriter来执行,如果它们拥有彼此的引用,就像下面的代码:

byte[] b1= ...

ClassReadercr = new ClassReader(b1);

ClassWritercw = new ClassWriter(cr, 0);

ChangeVersionAdapterca = new ChangeVersionAdapter(cw);

cr.accept(ca,0);

byte[] b2= cw.toByteArray();

?

经过优化,上面的代码将比前面例子中的代码快两倍。因为ChangeVersionAdapter没有转换任何方法。对于转换部分或者所有方法而言,这种对速度的提高虽然很小,但确实显著的,可以达到10%到20%。不幸地是,这种优化需要复制在原始类中定义的所有常量到转换后的类中。这对于在转换中增加字段,方法或者指令什么的不是一个问题,但是相对于未优化的情形,这会导致在大的类转换过程中删除或者重命名很多类的元素。因此,这种优化适合于需要添加代码的转换。

?

使用转换后的类

?

转换后的类b2可以保存到磁盘或者被ClassLoader加载,如前面章节描述的。但是在一个ClassLoader中只能转换被该ClassLoader加载的类。如果你想转换所有的类,你需要把转换的代码放置到一个ClassFileTransformer中,该类定义在java.lang.instrment包中(可以参看该报的文档获得详细信息):

public static void premain(StringagentArgs, Instrumentation inst) {

???????? inst.addTransformer(newClassFileTransformer() {

?????????????????? publicbyte[] transform(ClassLoader l, String name, Class c,

??????????????????????????? ProtectionDomaind, byte[] b)throws IllegalClassFormatException {

??????????????????????????? ClassReadercr = new ClassReader(b);

??????????????????????????? ClassWritercw = new ClassWriter(cr, 0);

??????????????????????????? ClassVisitorcv = new ChangeVersionAdapter(cw);

??????????????????????????? cr.accept(cv,0);

??????????????????????????? returncw.toByteArray();

??????????????????????????? }

???????? });

}

读书人网 >编程

热点推荐