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的方法體






 

 

 

posted @ 2012-02-29 17:29  秋日私语的博客  阅读(3687)  评论(2编辑  收藏  举报