什么是ASM?
引用ASM官方的介绍:
ASM是一个通用的Java字节码操作和分析框架。它可以直接以二进制形式用于修改现有类或动态生成类。ASM提供了一些常见的字节码转换和分析算法,可以从中构建定制的复杂转换和代码分析工具。ASM提供了与其他Java字节码框架类似的功能,但主要关注性能。由于它的设计和实现尽可能小,速度尽可能快,因此非常适合在动态系统中使用(当然,也可以以静态方式使用,例如在编译器中)。
说白了就是我们可以通过使用ASM框架,来读取和修改.class文件。相比JDK反射技术来说,ASM提供了更方便的字节码读取方式,性能上也更加高效。
简单了解如何使用ASM框架
在ASM框架中有两个主要的类,一个是ClassVisitor,一个是ClassReader。
ClassReader接收一个输入流,读取.class文件时通过accept方法回调ClassVisitor的各类visit开头的方法;
InputStream is = new BufferedInputStream(resource.getInputStream());
ClassReader classReader = new ClassReader(is);
classReader.accept(visitor, ClassReader.SKIP_DEBUG);
通过继承ClassVisitor类,重写父类visit开头的方法
public class TClassMetadataReadingVisitor extends ClassVisitor {
public TClassMetadataReadingVisitor(int api) {
super(Opcodes.ASM6);
}
//读取类基础信息时调用的回调方法,版本、类名、父类名、接口名等
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
}
//读取内部类时调用的回调方法
@Override
public void visitOuterClass(String owner, String name, String descriptor) {
super.visitOuterClass(owner, name, descriptor);
}
}
ClassVisitor类下的方法还有很多,这里只做简单举例说明;
Spring中ASM框架的使用
Spring中与ASM直接相关的类即为ClassMetadataReadingVisitor类;
ClassMetadataReadingVisitor,这里省略get/set方法
class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata {
private String className = "";
private boolean isInterface;
private boolean isAnnotation;
private boolean isAbstract;
private boolean isFinal;
@Nullable
private String enclosingClassName;
private boolean independentInnerClass;
@Nullable
private String superClassName;
private String[] interfaces = new String[0];
private Set<String> memberClassNames = new LinkedHashSet<>(4);
public ClassMetadataReadingVisitor() {
super(SpringAsmInfo.ASM_VERSION);
}
@Override
public void visit(
int version, int access, String name, String signature, @Nullable String supername, String[] interfaces) {
this.className = ClassUtils.convertResourcePathToClassName(name);
this.isInterface = ((access & Opcodes.ACC_INTERFACE) != 0);
this.isAnnotation = ((access & Opcodes.ACC_ANNOTATION) != 0);
this.isAbstract = ((access & Opcodes.ACC_ABSTRACT) != 0);
this.isFinal <