今天在看Thinking in Java的时候,配置工程出现错误:
java: 程序包javassist不存在
原因就像错误描述的那样,缺少javassist.jar包。本来应该是不值一提的错误,但是hankcs还是初次接触这个javassist.jar,还是得查查做个memo。它是JBoss的一个子项目,可以直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。你可以在这里下载到。这玩意儿可真是个狠家伙,可以动态生成\注入代码,修改已有的代码。令我回忆起windows上的线程注入dll注入了。
Talking is cheap,show me the code:-D
假设我有一个class A
package com.hankcs; import java.util.Arrays; /** * @author Hankcs */ public class A { private int[] a = new int[]{23, 35, 46, 12, 99, 48, 74}; public void foo(int n) { //示意性的代码表示业务逻辑 for (int i = 0; i < n; i++) { Arrays.sort(a); } System.out.println("class A.foo()"); } }
我想要在程序中动态改变A的代码,利用javassist.jar可以轻易做到:
package com.hankcs; import javassist.*; public class Main { public static void main(String[] args) throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException { // 获取com.hankcs.A这个类 CtClass cc = ClassPool.getDefault().get("com.hankcs.A"); // 获取A类中的foo方法 CtMethod method = cc.getDeclaredMethod("foo"); // 重新取个名字,待会儿还要调用 method.setName("foo$impl"); // 将foo方法复制出一个新的方法,新方法与元方法一摸一样 CtMethod newMethod = CtNewMethod.copy(method, "foo", cc, null); // 用字串写动态代码 StringBuilder sb = new StringBuilder(); sb.append("{\n"); sb.append(" long start = System.currentTimeMillis();\n"); sb.append(" foo$impl($$);\n"); sb.append(" long end = System.currentTimeMillis();\n"); sb.append(" System.out.println(\"Time interval = \" + (end - start) + \"ms\");\n"); sb.append("}\n"); // 将动态代码设为newMethod的Body newMethod.setBody(sb.toString()); // 动态加入到类 cc.addMethod(newMethod); // 生成实例 A a = (A) cc.toClass().newInstance(); // 输出Time interval = a.foo(10000000); // 依然输出Time interval = A b = new A(); b.foo(10000000); } }
输出:
class A.foo() Time interval = 244ms class A.foo() Time interval = 192ms Process finished with exit code 0
工程下载:http://pan.baidu.com/s/1BsHRh
参考http://hi.baidu.com/jackfrued/item/be340ce278b5daa8c10d75a1