相似字节码操做方法还有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的核心类:框架
JavaAssit的核心类:性能
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"); } }