java类加载及动态代理之ASM框架

本文学习一下java有关字节码的技术以及实现它的框架之一ASM,首先介绍一下字节码技术,其实从jvm的类加载机制就可以发现,jvm执行的不是java源文件而是编译之后的.class文件,而这个文件就是基于二进制的字节码文件。那我们学会这个有什么好处呢?用处很多,举个例子来说 可以完全自己手动实现一个class文件,然后调用classloader来加载它..这样一来可以做很多之外的事情.

ASM是什么?

ASM 是一个 Java 字节码操纵框架。它可以直接以二进制形式动态地生成 stub 类或其他代理类,或者在装载时动态地修改类。ASM 提供类似于 BCEL 和 SERP 之类的工具包的功能,但是被设计得更小巧、更快速,这使它适用于实时代码插装。

ASM相当小巧,并且它有更高的执行效率,是BCEL的7倍,SERP的11倍以上(摘自网络,具体没有测试)。目前ASM已被广泛的开源应用架构所使用,例如:Spring、Hibernate

CLASS的根节点的层次了解:因为它是完全基于这个进行动态字节码实现的

  • ConstantPool:符号表
  • FieldInfo:类中的成员变量信息;
  • MethodInfo:类中的方法描述;
  • Attribute:可选的附加节点。

      FieldInfo节点包含成员变量的名称,诸如public,private,static等的标志。

      ConstantValue属性用来存储静态的不变的成员变量的值。

      Deprecated和Synthetic被用来标记一个成员变量是不被推荐的或由编译器生成的。

      MethodInfo节点包含方法的名称,参数的类型和和它的返回值,方法是公有的,私有的或静态的等标志。

      MethodInfo包含可选的附加属性,其中最重要的是Code属性,它包含非抽象的方法的代码。

扫描二维码关注公众号,回复: 1679238 查看本文章

      Exceptions属性包含方法将抛出的Exception的名称。

ASM常用的两个类:

ClassWriter:类对象

ClassVisitor:类方法对象

下面通过ASM实现一个简单的class生成:

import java.io.File;
import java.io.FileOutputStream;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
 * Created by jack on 2018/6/19.
 * 通过使用asm框架 动态生成class文件
 */
public class PersonClassAsm {
    public static void main(String[] args) throws Exception{
        System.out.println();
        ClassWriter classWriter = new ClassWriter(0);
        // 通过visit方法确定类的头部信息
        classWriter.visit(Opcodes.V1_7,// java版本
                Opcodes.ACC_PUBLIC,// 类修饰符
                "Programmer", // 类的全限定名
                null, "java/lang/Object", null);

        //创建构造函数
        MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>","()V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();

        // 定义code方法
        MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "eat", "()V",
                null, null);
        methodVisitor.visitCode();
        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out",
                "Ljava/io/PrintStream;");
        methodVisitor.visitLdcInsn("i am person ,i like to eating.....");
        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                "(Ljava/lang/String;)V");
        methodVisitor.visitInsn(Opcodes.RETURN);
        methodVisitor.visitMaxs(2, 2);
        methodVisitor.visitEnd();
        classWriter.visitEnd();
        // 使classWriter类已经完成
        // classWriter转换成字节数组写到文件里面去
        byte[] data = classWriter.toByteArray();
        String path ="/soft/idea/workspace/java_dynamic_proxy/src/main/java/com/suning/dynamic_proxy/asm/Person.class";
        File file = new File(path);
        FileOutputStream fout = new FileOutputStream(file);
        fout.write(data);
        fout.close();
    }

上面就是通过动态字节码实现了一个class文件,源文件内容如下:

/**
 * Created by jack on 2018/6/19.
 */
public class Person {
    public void eat(){
        System.out.println("i am person,i like to eat banana...");
    }
}
 
 

总结一下:

优点:ASM体积很轻巧,编译速度也较快,完全可以实现动态的class文件

缺点:它是基于JVM底层的汇编指令的,所以要熟悉JVM底层的汇编指令,这个编写起来比较麻烦,对于新手而言,叫困难

猜你喜欢

转载自blog.csdn.net/qq_18603599/article/details/80747281