java代理的深刻淺出(三)-JavaAssist,ASM

簡介

相似字節碼操做方法還有ASM。幾種動態編程方法相比較,在性能上Javassist高於反射,但低於ASM,由於Javassist增長了一層抽象。在實現成本上Javassist和反射都很低,而ASM因爲直接操做字節碼,相比Javassist源碼級別的api實現成本高不少。幾個方法有本身的應用場景,好比Kryo使用的是ASM,追求性能的最大化。而NBeanCopyUtil採用的是Javassist,在對象拷貝的性能上也已經明顯高於其餘的庫,並保持高易用性。實際項目中推薦先用Javassist實現原型,若在性能測試中發現Javassist成爲了性能瓶頸,再考慮使用其餘字節碼操做方法作優化。java

ASM 是一個 Java 字節碼操控框架。它可以以二進制形式修改已有類或者動態生成類。ASM 能夠直接產生二進制 class 文件,也能夠在類被加載入 Java 虛擬機以前動態改變類行爲。ASM 從類文件中讀入信息後,可以改變類行爲,分析類信息,甚至可以根據用戶要求生成新類。
不過ASM在建立class字節碼的過程當中,操縱的級別是底層JVM的彙編指令級別,這要求ASM使用者要對class組織結構和JVM彙編指令有必定的瞭解。編程

JavaAssist和Asm都是一種在運行時,修改字節碼的框架,以下圖所示
api

JavaAssit和Asm的核心類:框架

  • ClassWriter
  • MethodVisitor

JavaAssit的核心類:性能

  • ClassPool
  • CtClass
  • CtMethod

示例

ASM:採用適配模式修改類測試

public class TestAsm {

    public static void main(String[] args) throws IOException {
        ClassReader classReader = new ClassReader("com.longchao.asm.TestClass");
        ClassWriter classWriter = new ClassWriter(classReader, 0);
        ClassVisitor classVisitor = new ProgrammerClassAdapter(classWriter);
        classReader.accept(classVisitor, 0);
         
    }
}

public class ProgrammerClassAdapter  extends ClassAdapter{
    public ProgrammerClassAdapter(ClassVisitor classVisitor) {
        super(classVisitor);
    }
    public MethodVisitor visitMethod(int access,String name,String desc,String signature,String[] exceptions){
        MethodVisitor methodVisitor = cv.visitMethod(access,name,desc,signature,exceptions);
        if(null != methodVisitor&& "doCoding".equals(name)){
            methodVisitor = new DoCodingMethodAdapter(methodVisitor);
            return methodVisitor;

        }
        return methodVisitor;
    }
}

public class DoCodingMethodAdapter extends MethodAdapter {

    public DoCodingMethodAdapter(MethodVisitor arg0){
        super(arg0);
    }

    public void visitCode(){
        super.visitCode();
        mv.visitFieldInsn(Opcodes.GETSTATIC,"System","out","Ljava/io/PrintStream");
        mv.visitLdcInsn("doAsmCode............");
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/String;)V");

    }   

}

JavaAssit的示例優化

public class TestJavaAssist {
    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        //建立Programmer類
        CtClass cc= pool.makeClass("com.longchao.Programmer");
        //定義code方法
        CtMethod method = CtNewMethod.make("public void code(){}", cc);
        //插入方法代碼
        method.insertBefore("System.out.println(\"I'm a Programmer,Just Coding.....\");");
        cc.addMethod(method);
        //保存生成的字節碼
        cc.writeFile("d://temp");
    }
}
相關文章
相關標籤/搜索