java class 被存儲在嚴格格式定義的.class文件裏,這些類文件擁有足夠的元數據來解析類中全部元素: 類名稱,方法,屬性,java字節碼指令。 ASM從類文件中讀取以上信息,並提供了訪問和修改這些信息的接口,進而改變類原有行爲。 對於ASM來講,java class被描述爲一棵樹,ASM使用Visitor模式遍歷整個二進制結構。java
反射,Proxy,元數據,ASM庫幫助Java實現了動態語言的能力。git
Proxy必須基於接口,Cglib不須要。github
若是對類的修改是一次性的且原始類信息是可知的,能夠經過ASM直接編譯出修改過的class文件並保存到硬盤,以後運行再也不依賴ASM,和普通類沒有區別,這種方式一般須要自定義ClassLoader。api
若是不但願改變類原有功能,只是在運行期間修改/添加一些類信息,好比動態代理,AOP等,能夠在啓動時往Java虛擬機中掛一個用戶定義的hook程序,在裝入特定類的時候使用ASM改變特定類的字節碼,從而改變類行爲。this
public class TestBean { public void asmEcho(){ System.out.println("hello asm"); } }
public class AopInteceptor { public static void before(){ System.out.println(".......before()......."); } public static void after(){ System.out.println(".......after()......."); } }
public class AopClassAdapter extends ClassVisitor implements Opcodes { public AopClassAdapter(int i, ClassVisitor classVisitor) { super(i, classVisitor); } public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { //更改類名,並使新類繼承原有的類。 super.visit(version, access, name + "_tmp", signature, name, interfaces); {//輸出一個默認的構造方法 MethodVisitor mv = super.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, name, "<init>", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } } public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { if ("<init>".equals(name)) return null;//放棄原有類中全部構造方法 if (!name.startsWith("asm")) return null;// 只對asm開始的方法執行代理 MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); return new AopMethodVisitor(this.api, mv); } }
public class AopMethodVisitor extends MethodVisitor implements Opcodes { public AopMethodVisitor(int i, MethodVisitor methodVisitor) { super(i, methodVisitor); } public void visitCode(){ super.visitCode(); this.visitMethodInsn(INVOKESTATIC,"com/xxx/beecho/framework/asm/AopInteceptor","before","()V",false); } public void visitInsn(int opcode) { if (opcode >= IRETURN && opcode <= RETURN)//在方法返回以前 { this.visitMethodInsn(INVOKESTATIC, "com/xxx/beecho/framework/asm/AopInteceptor", "after", "()V", false); } super.visitInsn(opcode); } }
public class AopClassLoader extends ClassLoader implements Opcodes { public AopClassLoader() { super(); } public AopClassLoader(ClassLoader parent) { super(parent); } public Class<?> loadClass(String name) throws ClassNotFoundException { if (!name.endsWith("_tmp")) return super.loadClass(name); try { ClassWriter cw = new ClassWriter(0); InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/xxx/beecho/framework/asm/TestBean.class"); ClassReader reader = new ClassReader(is); reader.accept(new AopClassAdapter(ASM4, cw), ClassReader.SKIP_DEBUG); byte[] code = cw.toByteArray(); // // ----- // FileOutputStream fos = new FileOutputStream("E:\\code\\java\\TestBean_tmp.class"); // fos.write(code); // fos.flush(); // fos.close(); return this.defineClass(name, code, 0, code.length); } catch (Throwable e) { e.printStackTrace(); throw new ClassNotFoundException(); } // return null; } }
public static void main( String[] args ) throws IOException { try { AopClassLoader classLoader = new AopClassLoader(); Class<?> asmClass = classLoader.loadClass("com.xxx.beecho.framework.asm.TestBean_tmp"); Object obj = asmClass.newInstance(); Method method = asmClass.getMethod("asmEcho",null); method.invoke(obj,null); } catch (Exception e) { e.printStackTrace(); } }
.......before()....... hello asm .......after().......
https://github.com/zhangcj/code-example/tree/master/framework/src/main/java/com/xxx/beecho/framework代理