ASM技术
如果用反射的方式去获取类的注解,那么需要把所有路径下的class文件加入到jvm中解析,消耗巨大
spring中的ASM使用主要就是visotor(访问者)模式,直接先读取原来的文件,相当于reader,然后通过adapter,自己定制一套写法,最后再写入到一个新文件中,相当于改变了原有代码,增加了切面,
asm是什么
ASM是一个JAVA字节码操控框架.它能被用来动态生成类或者增加既有类的功能.ASM可以直接产生二进制class文件,也可以在类被载入java虚拟机之前动态改变行为.java class被存储在严格定义的.class文件里.这些类文件拥有足够的元数据来解析类中的所有元素,类名,方法名,属性,以及java字节码.ASM从类文件读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类.说白了ASM直接通过字节码来修改class文件(俗称字节码插装)
具体来说,Spring的AOP,可以通过JDK的动态代理来实现,也可以通过CGLIB实现。其中,CGLib (Code Generation Library)是在ASM的基础上构建起来的(当然JDK Proxy也是一样的),所以,Spring AOP是间接的使用了ASM。
ASM不是什么的缩写,那名称是怎么来的呢?一般而言在c语言中通常会有一个asm类,约定俗成的在里面写一些汇编语言
ASM 跟AOP三剑客的关系
APT、aspectJ、Javassit有什么关系?
APT(Annotation Processing Tool)即注解处理器,是一种处理注解的工具,确切的说它是javac的一个工具,它用来在编译时扫描和处理注解。注解处理器以Java代码(或者编译过的字节码)作为输入,生成.java文件作为输出。简单来说就是在编译期,通过注解生成.java文件
aspectJ:AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的[编译器]用来生成遵守Java字节编码规范的Class文件。适合在某一个方法前后插入部分代码,处理某些逻辑:比如方法运行时间、插入动态权限检查等。问题会造成很多的冗余代码,产生很多代理类。简单来说就是在生成class时动态织入代码
Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba(千叶滋)所创建的。简单来说就是源码级别的api去修改字节码

ASM如何处理字节码(ByteCode)数据
ASM处理字节码的方式是,拆分-修改-合并
思路是
- 将文件拆分成多个部分
- 对某一个部分的信息进行修改
- 将多个部分重新组织称一个新的class文件
API
Core API
ASM Core APi可以类比XML文件中SAX方式,不需要把这个类的整个结构读取出来,就可以用流式的方法来处理字节码文件.好处是非常节约内存,但是编程难度较大.然而出于性能考虑,一般情况下编程都是用Core Api 其中包含的几个关键类如下
- ClassReader:用于读取class文件
- ClassWriter:用于修改class文件,如修改类名,属性以及方法;或生成新的class文件
- ClassVisitor:抽象类,可以对注解变量方法解析,对应的具体子类分别是AnnotationVisitor,FieldVisitor,MethodVisitor(会解析方法上的注解,参数,代码等)

TreeApi
ASM three API可以类比解析XML文件中的DOM方式,把整个类的结构读取到内存中,缺点是消耗内存多,但编程比较简单.TreeApi不同于CoreApi,TreeApi通过各种Node类来映射字节码各个区域
使用
引入
安装


代码
Human
查看到的字节码为
CreateHuman
运行后正常输出
Hello world!
null
Hello StringBuilder!
3注意
ClassWriter(ClassWriter.COMPUTE_FRAMES),这个ClassWriter的flag参数,建议设置COMPUTE_FRAMES,按照官网所说,性能虽然差点,但是可以自动更新操作数栈和方法调用帧计算,这时候methodVisitor.visitMaxs(0, 0)里面的参数就可以随便写了,但这个方法必须要调用,不然即使生成了class,在执行这个class中的方法时会报错。具体说明可以看jar中的注释。
| Java 类型 | 类型描述符 |
|---|---|
| boolean | Z |
| char | C |
| byte | B |
| short | S |
| int | I |
| float | F |
| long | J |
| double | D |
| Object | Ljava/lang/Object; |
| int[] | [I |
| Object[][] | [[Ljava/lang/Object; |
| 源文件中的方法声明 | 方法描述符 |
|---|---|
| void m(int i, float f) | (IF)V |
| int m(Object o) | (Ljava/lang/Object;)I |
| int[] m(int i, String s) | (ILjava/lang/String;)[I |
| Object m(int[] i) | ([I)Ljava/lang/Object; |