java 动态AOP
3539 点击·0 回帖
![]() | ![]() | |
![]() | 一、實現機制: 在运行期,所有类加载器加载字节码前,前进行拦截。並將代碼植入。可以对所有类进行织入。 二、實現方式: 1. 實現ClassFileTransformer 接口 2. 添加以下方法(必須): public static void premain(String options, Instrumentation ins) { //注册我自己的字节码转换器 ins.addTransformer(new MyClassFileTransformer()); } 實例: 1 package com.aop; 2 3 import java.io.IOException; 4 import java.lang.instrument.ClassFileTransformer; 5 import java.lang.instrument.IllegalClassFormatException; 6 import java.lang.instrument.Instrumentation; 7 import java.security.ProtectionDomain; 8 9 import javassist.CannotCompileException; 10 import javassist.ClassPool; 11 import javassist.CtClass; 12 import javassist.CtMethod; 13 import javassist.NotFoundException; 14 15 public class AopTransformer implements ClassFileTransformer { 16 17 /** 18 * 字节码加载到虚拟机前会进入这个方法 19 */ 20 @Override 21 public byte[] transform(ClassLoader loader, String className, 22 Class<?> classBeingRedefined, ProtectionDomain protectionDomain, 23 byte[] classfileBuffer) throws IllegalClassFormatException { 24 25 // javassist的包名是用点分割的,需要转换下 26 if (className.indexOf("/") != -1) { 27 className = className.replaceAll("/", "."); 28 } 29 30 try { 31 // 通过包名获取类文件 32 CtClass cc = ClassPool.getDefault().get(className); 33 34 // 获得指定方法名的方法 35 CtMethod m = cc.getDeclaredMethod("sayhello"); 36 37 // 在方法执行前插入代码 38 m.insertBefore("{System.out.println(\"在HelloTest.sayhello之前執行\");}"); 39 m.insertAfter("{System.out.println(\"在HelloTest.sayhello之後執行\");}"); 40 m = cc.getDeclaredMethod("sayGoodBye"); 41 42 // 在方法执行前插入代码 43 m.setBody("{System.out.println(\"修改HelloTest.sayGoodBye的方法體\");}"); 44 return cc.toBytecode(); 45 } catch (NotFoundException e) { 46 } catch (CannotCompileException e) { 47 e.printStackTrace(); 48 } catch (IOException e) { 49 // 忽略异常处理 50 } 51 return null; 52 } 53 54 /** 55 * 在main函数执行前,执行的函数 56 * 57 * @param options 58 * @param ins 59 */ 60 public static void premain(String options, Instrumentation ins) { 61 // 注册我自己的字节码转换器 62 ins.addTransformer(new AopTransformer()); 63 } 64 } 1 package com.test; 2 3 public class HelloTest { 4 public void sayhello() { 5 System.out.println("HelloTest sayhello"); 6 } 7 public void sayGoodBye() { 8 System.out.println("HelloTest sayGoodBye"); 9 } 10 11 public static void main(String[] args) { 12 HelloTest ht = new HelloTest(); 13 ht.sayhello(); 14 ht.sayGoodBye(); 15 } 16 } 三、執行 1. 需要告诉JVM在启动main函数之前,需要先执行premain函数。首先需要将premain函数所在的类打成jar包。并修改该jar包里的META-INF\MANIFEST.MF 文件,MANIFEST.MF 文件內容如下: 1 Manifest-Version: 1.0 2 Premain-Class: com.aop.AopTransformer 3 Can-Redefine-Classes: true 4 Can-Retransform-Classes: true 5 Can-Set-Native-Method-Prefix: true 2. 將aop.jar放到同一目錄 3. 使用java命令執行main方法: java -javaagent:.\aop.jar HelloTest 4. 執行結果比較 如果沒有添加aop執行結果如下: HelloTest sayhello HelloTest sayGoodBye 添加aop執行結果如下: 在HelloTest.sayhello之前執行 HelloTest sayhello 在HelloTest.sayhello之後執行 修改HelloTest.sayGoodBye的方法體 | |
![]() | ![]() |