简单看看ASM框架

什么是ASM

ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

一句话,ASM能够修改.class文件,从而动态生成类或者增强现有类的功能。

那问题来了,为什么需要动态生成类呢?

假设有这样一个需求,对现有的业务逻辑增加日志记录功能。最简单的做法自然就是直接在逻辑后面加日志记录,但是比较繁杂。Spring AOP中的经典应用就可以解决类似的问题。

动态改变 Java 类就是要解决 AOP 的问题,提供一种得到系统支持的可编程的方法,自动化地生成或者增强 Java 代码。

实现这样的需求,可以用JDK原生的动态代理,网上资料很多,这里就不举例了。但是有不足的地方,Proxy 是面向接口的,所有使用 Proxy 的对象都必须定义一个接口,这对于编程有比较大的限制。

ASM 能够通过改造既有类,直接生成需要的代码。增强的代码是硬编码在新生成的类文件内部的,没有反射带来性能上的付出。同时,ASM 与 Proxy 编程不同,不需要为增强代码而新定义一个接口,生成的代码可以覆盖原来的类,或者是原始类的子类。它是一个普通的 Java 类而不是 proxy 类,甚至可以在应用程序的类框架中拥有自己的位置,派生自己的子类。

另外一种实现动态代理的框架cglib底层也是基于ASM的。

在《深入理解Java虚拟机》一书中第六章,有关于类文件结构的详细解读。Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容几乎全部都是程序运行的必要数据。因为Java虚拟机中要求Class文件中强制性的语法和结构化约束,这就实现了语言的无关性,这也让像Groovy程序等也可以跑在Java虚拟机中。

个人理解,Class文件结构有点类似自己在基于TCP协议上面自定义的网络协议,哪几个字节是干嘛干嘛用,定义一大串。然后客户端读的时候,也是按照这个规则去读的。

在ASM框架中,类的数量并不是很多。

ClassReader:这个类可以直接由字节数组或由 class 文件间接的获得字节码数据,它能正确的分析字节码,构建出抽象的树在内存中表示字节码。它会调用 accept方法,这个方法接受一个实现了 ClassVisitor接口的对象实例作为参数,然后依次调用 ClassVisitor接口的各个方法。字节码空间上的偏移被转换成 visit 事件时间上调用的先后,所谓 visit 事件是指对各种不同 visit 函数的调用,ClassReader知道如何调用各种 visit 函数。

ClassAdaptor: 实现了 ClassVisitor接口所定义的所有函数,当新建一个 ClassAdaptor对象的时候,需要传入一个实现了 ClassVisitor接口的对象,作为职责链中的下一个访问者 (Visitor),这些函数的默认实现就是简单的把调用委派给这个对象,然后依次传递下去形成职责链。当用户需要对字节码进行调整时,只需从 ClassAdaptor类派生出一个子类,覆写需要修改的方法,完成相应功能后再把调用传递下去。这样,用户无需考虑字节偏移,就可以很方便的控制字节码。

ClassWriter:ASM 的最终的目的是生成可以被正常装载的 class 文件,实现了 ClassVisitor接口,而且含有一个 toByteArray()函数,返回生成的字节码的字节流,将字节流写回文件即可生产调整后的 class 文件。

public interface ClassVisitor {
    //visit( 类版本 ,修饰符 , 类名 , 泛型信息 , 继承的父类 , 实现的接口)
    void visit(int var1, int var2, String var3, String var4, String var5, String[] var6);
    //
    void visitSource(String var1, String var2);

    void visitOuterClass(String var1, String var2, String var3);
    //visitAnnotation(注解类型 , 注解是否可以在 JVM 中可见)。
    AnnotationVisitor visitAnnotation(String var1, boolean var2);

    void visitAttribute(Attribute var1);

    void visitInnerClass(String var1, String var2, String var3, int var4);
    //visitField(修饰符 , 字段名 , 字段类型 , 泛型描述 , 默认值)
    FieldVisitor visitField(int var1, String var2, String var3, String var4, Object var5);
    //visitMethod(修饰符 , 方法名 , 方法签名 , 泛型信息 , 抛出的异常)。
    //方法签名,方法签名的格式如下:“(参数列表)返回值类型”。在字节码中不同的类型都有其对应的代码
    MethodVisitor visitMethod(int var1, String var2, String var3, String var4, String[] var5);

    void visitEnd();
}

感觉还是比较理解,先记录一下,以后再学习学习。

你可能感兴趣的:(简单看看ASM框架)