使用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 }
