ASM是怎样访问及修改编译了的class文件
发布网友
发布时间:2022-04-28 22:54
我来回答
共1个回答
热心网友
时间:2022-06-24 17:18
ASM是基于ClassVisitor接口方法的调用顺序,提供了3个核心组件,用于产生和修改转换class
ClassReader解析compiled class的byte数组,其accept方法接受classVisitor的实例参数,按顺序调用它的各个visitXxx方法。将它作为事件的生产者。
ClassWriter直接构建二进制形式的class,toByteArray返回compiled class的byte数组。将它作为事件的消费者
ClassAdapter内部包装了一个ClassVisitor实例,代理所有的ClassVisitor接口方法。将它作为事件过滤器。
package org.objectweb.asm;
public abstract interface ClassVisitor
{
public abstract void visit(int paramInt1, int paramInt2, String paramString1, String paramString2, String paramString3, String[] paramArrayOfString);
public abstract void visitSource(String paramString1, String paramString2);
public abstract void visitOuterClass(String paramString1, String paramString2, String paramString3);
public abstract AnnotationVisitor visitAnnotation(String paramString, boolean paramBoolean);
public abstract void visitAttribute(Attribute paramAttribute);
public abstract void visitInnerClass(String paramString1, String paramString2, String paramString3, int paramInt);
public abstract FieldVisitor visitField(int paramInt, String paramString1, String paramString2, String paramString3, Object paramObject);
public abstract MethodVisitor visitMethod(int paramInt, String paramString1, String paramString2, String paramString3, String[] paramArrayOfString);
public abstract void visitEnd();
}
访问ClassVisitor接口方法的顺序:
visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )*
( visitInnerClass | visitField | visitMethod )*
visitEnd
首先必须调用visit, 然后最多访问一次visitSource, 然后最多调用一次visitOuterClass, 然后选出visitAnnotation或者visitAttribute之一,对它访问若干次,
然后选出visitInnerClass或者visitField或者visitMethod 之一, 对它调用若干次
最后必须调用一下visitEnd
以下例子说明了ClassReader如何使用accept方法, 依次按照所谓的顺序,调用 ClassPrinter作为ClassVisitor的实现类的visitXxx方法,访问java.util.Map的。
查看accept方法内部,可以发现这个所谓的调用顺序。
/**
* @{#} ClassPrinter.java Created on Jun 10, 2010 9:37:57 PM
*
* this code example from asm-guide.pdf
* author.
*
*/
package example.me;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
public class ClassPrinter implements ClassVisitor {
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
System.out.println(name + " extends " + superName + " {");
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return null;
}
public void visitAttribute(Attribute attr) {}
public void visitEnd() {
System.out.println("}");
}
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
System.out.println(" " + desc + " " + name);
return null;
}
public void visitInnerClass(String name, String outerName,
String innerName, int access) {}
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
System.out.println(" " + name + desc);
return null;
}
public void visitOuterClass(String owner, String name, String desc) {}
public void visitSource(String source, String debug) {}
public static void main(String[] args) throws Exception {
ClassPrinter cp = new ClassPrinter();
ClassReader cr = new ClassReader("java.util.Map");
/*
* InputStream input = Thread.currentThread().getContextClassLoader()
* .getResourceAsStream( "java.lang.Runnable".replace('.', '/') +
* ".class"); ClassReader cr = new ClassReader(input);
*/
cr.accept(cp, 0); //cp是ClassVisitor的实现类,在accept方法的内部,以既定的顺序调用cp.visitXxx(...)方法,最终输出java.util.Map的编译后class结构
}
}
输出结果:java/util/Map extends java/lang/Object {
size()I
isEmpty()Z
containsKey(Ljava/lang/Object;)Z
containsValue(Ljava/lang/Object;)Z
get(Ljava/lang/Object;)Ljava/lang/Object;
put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
remove(Ljava/lang/Object;)Ljava/lang/Object;
putAll(Ljava/util/Map;)V
clear()V
keySet()Ljava/util/Set;
values()Ljava/util/Collection;
entrySet()Ljava/util/Set;
equals(Ljava/lang/Object;)Z
hashCode()I
}