赞
踩
ASM是一个通用的Java字节码操作和分析框架,它可以用来修改现有的类或直接以二进制形式动态生成类。ASM提供了一些常见的字节码转换和分析算法,从中可以构建定制的复杂转换和代码分析工具。ASM提供了与其他Java字节码框架类似的功能,但侧重于性能。因为它的设计和实现都尽可能小和快,所以它非常适合在动态系统中使用(当然也可以以静态方式使用,例如在编译器中)。
ASM被用在很多项目中,包括如下:
更多参考官网:https://asm.ow2.io/
ASM是直接对字节码进行操作,如果不熟悉字节码操作集合的话,写起来会很费劲,所以ASM为主流的IDE专门提供了开发插件BytecodeOutline:
以IDEA为例,只需要对应的类中右击->Show Bytecode outline即可,大致如下图所示:
面板中包含三个页签:
Bytecode
:类对应的字节码文件;ASMified
:利用ASM
生成字节码对应的代码;Groovified
:类对应的字节码指令;ASM
库提供了两个用于生成和转换已编译类的API
,一个是核心API
,以基于事件的形式来表示类;另一个是树API
,以基于对象的形式来表示类;可以对比XML
文件解析的方式:SAX
模式和DOM
模式;核心API对应SAX
模式,树API
对应DOM
模式;每种模式都有自己的优缺点:
ASM
库组织在几个包中,这些包分布在几个单独的JAR文件中:
org.objectweb.asm
和org.objectweb.asm.signature
包:定义基于事件的API并提供类解析器和编写器组件,它们包含在asm.jar中;org.objectweb.asm.util
包:提供基于核心API的各种工具,这些工具可在ASM应用程序的开发和调试过程中使用,包含在asm-util.jar
中;org.objectweb.asm.commons
包:提供了几个有用的预定义类转换器,主要基于核心API,包含在asm-commons.jar
中;org.objectweb.asm.tree
包:定义基于对象的API,并提供用于在基于事件的表示和基于对象的表示之间进行转换的工具,包含在asm-tree.jar
中;org.objectweb.asm.tree.analysis
包:包提供了一个基于树API的类分析框架和几个预定义的类分析器,包含在asm-analysis.jar
中;在学习核心API
之前,建议了解一下访问者模式,因为ASM
对字节码的操作和分析都是基于访问者模式来实现的;
访问者模式建议将新行为放入一个名为访问者的独立类中, 而不是试图将其整合到已有类中。现在, 需要执行操作的原始对象将作为参数被传递给访问者中的方法, 让方法能访问对象所包含的一切必要数据;常见的应用场景:
字节码其实就是一个复杂的对象结构,还有像Sharding-Jdbc
中对sql
的解析也用到访问者模式,可以发现都是一些数据结构比较稳定的数据,固定的语法;
更多参考:访问者模式
访问者模式有两个核心类分别是:独立的访问者、接收访问者事件产生器;对应的ASM
里面就是两个核心类:ClassVisitor
和ClassReader
,下面分别进行介绍;
用于生成和转换编译类的ASM API
基于ClassVisitor
抽象类,这个类中的每个方法都对应于同名的类文件结构:
public abstract class ClassVisitor {
public ClassVisitor(int api);
public ClassVisitor(int api, ClassVisitor cv);
public void visit(int version, int access, String name,String signature, String superName, String[] interfaces);
public void visitSource(String source, String debug);
public void visitOuterClass(String owner, String name, String desc);
AnnotationVisitor visitAnnotation(String desc, boolean visible);
public void visitAttribute(Attribute attr);
public void visitInnerClass(String name, String outerName,String innerName, int access);
public FieldVisitor visitField(int access, String name, String desc,String signature, Object value);
public MethodVisitor visitMethod(int access, String name, String desc,String signature, String[] exceptions);
void visitEnd();
}
内容可以具有任意长度和复杂性的部件将通过返回辅助访问者类,主要包括:AnnotationVisitor
、FieldVisitor
、MethodVisitor
;更多可以参考Java 虚拟机规范
;
以上所有方法都会被事件产生器ClassReader
调用,所有方法中的参数都是ClassReader
提供的,当然调用每个方法是有顺序的:
visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )* ( visitInnerClass | visitField |visitMethod )* visitEnd
首先调用visit
,然后是对visitSource
的最多一个调用,接下来是对visitOuterClass
的最多一个调用 , 然后是可按任意顺序对 visitAnnotation
和visitAttribute
的任意多个访问 , 接下来是可按任意顺序对 visitInnerClass
、visitField
和 visitMethod
的任意多个调用,最后以一个visitEnd
调用结束。
此类主要功能就是读取字节码文件,然后把读取的数据通知ClassVisitor
,字节码文件可以多种方式传入:
public ClassReader(final InputStream inputStream)
:字节流的方式;public ClassReader(final String className)
:文件全路径;public ClassReader(final byte[] classFile)
:二进制文件;常见使用方式如下所示:
ClassReader classReader = new ClassReader("com/zh/asm/TestService");
ClassWriter classVisitor = new ClassWriter
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。