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代理