当前位置:编程学习 > JAVA >>

java 动态AOP

一、實現機制:
在运行期,所有类加载器加载字节码前,前进行拦截。並將代碼植入。可以对所有类进行织入。
二、實現方式:
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的方法體
 

摘自 zzhcoo

 

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,