java 动态AOP

来源:互联网 发布:开淘宝怎么交保证金 编辑:程序博客网 时间:2024/05/16 17:41

一、實現機制:

在运行期,所有类加载器加载字节码前,前进行拦截。並將代碼植入。可以对所有类进行织入。

二、實現方式:

1. 實現ClassFileTransformer 接口

2. 添加以下方法(必須):

 

public static void premain(String options, Instrumentation ins) {        //注册我自己的字节码转换器       ins.addTransformer(new MyClassFileTransformer());   }  

實例:

 

 

 

 

复制代码
package com.aop;
 
 import java.io.IOException;
 import java.lang.instrument.ClassFileTransformer;
 import java.lang.instrument.IllegalClassFormatException;
 import java.lang.instrument.Instrumentation;
 import java.security.ProtectionDomain;
 
 import javassist.CannotCompileException;
 import javassist.ClassPool;
 import javassist.CtClass;
 import javassist.CtMethod;
 import javassist.NotFoundException;
 
 public class AopTransformer implements ClassFileTransformer {
 
     /**
      * 字节码加载到虚拟机前会进入这个方法
 */
     @Override
     public byte[] transform(ClassLoader loader, String className,
             Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
             byte[] classfileBuffer) throws IllegalClassFormatException {
 
         // javassist的包名是用点分割的,需要转换下
         if (className.indexOf("/") != -1) {
             className = className.replaceAll("/", ".");
         }
         
         try {
             // 通过包名获取类文件
             CtClass cc = ClassPool.getDefault().get(className);
 
             // 获得指定方法名的方法
             CtMethod m = cc.getDeclaredMethod("sayhello");
 
             // 在方法执行前插入代码
             m.insertBefore("{System.out.println(\"在HelloTest.sayhello之前執行\");}");
             m.insertAfter("{System.out.println(\"在HelloTest.sayhello之後執行\");}");
             m = cc.getDeclaredMethod("sayGoodBye");
 
             // 在方法执行前插入代码
             m.setBody("{System.out.println(\"修改HelloTest.sayGoodBye的方法體\");}");
             return cc.toBytecode();
         } catch (NotFoundException e) {
         } catch (CannotCompileException e) {
             e.printStackTrace();
         } catch (IOException e) {
             // 忽略异常处理
         }
         return null;
     }
 
     /**
      * 在main函数执行前,执行的函数
      *
      * @param options
      * @param ins
 */
     public static void premain(String options, Instrumentation ins) {
         // 注册我自己的字节码转换器
         ins.addTransformer(new AopTransformer());
     }
 }

 

复制代码
 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.02 Premain-Class: com.aop.AopTransformer3 Can-Redefine-Classes: true4 Can-Retransform-Classes: true5 Can-Set-Native-Method-Prefix: true

2. 將aop.jar放到同一目錄

3. 使用java命令執行main方法:

 

java -javaagent:.\aop.jar HelloTest

 

 

4. 執行結果比較

 

如果沒有添加aop執行結果如下:

 

HelloTest sayhelloHelloTest sayGoodBye

添加aop執行結果如下:

 

在HelloTest.sayhello之前執行HelloTest sayhello在HelloTest.sayhello之後執行修改HelloTest.sayGoodBye的方法體