使用ASM生成Java字节码,下面通过java程序模拟实现spring aop 动态织入
Account.java
1 package com.market.search.test; 2 3 /** 4 * Created by xiaotian on 2018/5/8. 5 */ 6 public class Account { 7 public void operation() { 8 //通过字节码生成技术 动态添加check功能 模拟aop 动态织入 9 System.out.println("operation...."); 10 } 11 12 }
SecurityChecker.java
1 package com.market.search.test; 2 3 /** 4 * Created by xiaotian on 2018/5/8. 5 * 将checkSecurity 通过ASE方式动态 增强Account.operation 中 6 */ 7 public class SecurityChecker { 8 9 public static boolean checkSecurity() { 10 System.out.println("SecurityChecker.checkSecurity ..."); 11 return true; 12 } 13 14 }
AddSecurityCheckClassAdapter.java 类适配
1 package com.market.search.test; 2 3 import jdk.internal.org.objectweb.asm.ClassVisitor; 4 import jdk.internal.org.objectweb.asm.MethodVisitor; 5 import jdk.internal.org.objectweb.asm.Opcodes; 6 7 /** 8 * Created by xiaotian on 2018/5/8. 9 */ 10 public class AddSecurityCheckClassAdapter extends ClassVisitor { 11 public AddSecurityCheckClassAdapter( ClassVisitor cv) { 12 super(Opcodes.ASM5, cv); 13 } 14 // 重写 visitMethod,访问到 "operation" 方法时, 15 // 给出自定义 MethodVisitor,实际改写方法内容 16 public MethodVisitor visitMethod(final int access, final String name, 17 final String desc, final String signature, final String[] exceptions) { 18 MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions); 19 MethodVisitor wrappedMv = mv; 20 if (mv != null) { 21 // 对于 "operation" 方法 22 if (name.equals("operation")) { 23 // 使用自定义 MethodVisitor,实际改写方法内容 24 wrappedMv = new AddSecurityCheckMethodAdapter(mv); 25 } 26 } 27 return wrappedMv; 28 } 29 30 }
AddSecurityCheckMethodAdapter.java 方法适配
1 package com.market.search.test; 2 3 import jdk.internal.org.objectweb.asm.MethodVisitor; 4 import jdk.internal.org.objectweb.asm.Opcodes; 5 6 /** 7 * Created by xiaotian on 2018/5/8. 8 */ 9 public class AddSecurityCheckMethodAdapter extends MethodVisitor { 10 public AddSecurityCheckMethodAdapter(MethodVisitor mv) { 11 super(Opcodes.ASM5,mv); 12 } 13 public void visitCode() { 14 visitMethodInsn(Opcodes.INVOKESTATIC, "com/market/search/test/SecurityChecker", 15 "checkSecurity", "()Z"); 16 super.visitCode(); 17 } 18 19 }
Generator.java 测试生成字节码
1 package com.market.search.test; 2 3 import jdk.internal.org.objectweb.asm.ClassReader; 4 import jdk.internal.org.objectweb.asm.ClassWriter; 5 6 import java.io.File; 7 import java.io.FileOutputStream; 8 import java.net.URL; 9 import java.net.URLClassLoader; 10 11 /** 12 * Created by xiaotian on 2018/5/8. 13 */ 14 public class Generator { 15 private static AccountGeneratorClassLoader classLoader = new AccountGeneratorClassLoader(); 16 public static void main(String args[]) throws Exception { 17 ClassReader cr = new ClassReader("com.market.search.test.Account"); 18 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES); 19 AddSecurityCheckClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw); 20 cr.accept(classAdapter, ClassReader.SKIP_DEBUG); 21 22 byte[] data = cw.toByteArray(); 23 //File file = new File("C:\\Users\\xiaotian\\Desktop\\jvm原理\\Account.class"); 24 File file = new File("D:\\devlop\\workspace.market.new\\market-search-main-BL\\search-service_1.0.2_BR\\target\\classes\\com\\market\\search\\test\\Account.class"); 25 FileOutputStream fout = new FileOutputStream(file); 26 fout.write(data); 27 fout.close(); 28 29 // Class account = classLoader.defineClassFromClassFile("com.market.search.test.Account", data); 30 // Account acc =(Account) account.newInstance(); 31 // acc.operation(); 32 Account account = new Account(); 33 account.operation(); 34 35 36 } 37 private static class AccountGeneratorClassLoader extends ClassLoader { 38 public Class defineClassFromClassFile(String className, byte[] classFile) throws ClassFormatError { 39 return defineClass(className, classFile, 0,classFile.length); 40 } 41 } 42 }