莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          使用javassist對.class文件進行修改

          Posted on 2007-02-06 12:44 dennis 閱讀(806) 評論(0)  編輯  收藏 所屬分類: java

          最近重新再看<Inside JVM>,對JAVA編譯成的字節碼結構很感興趣,希望找個工具能夠對.class文件進行的解析和查看。沒找到,倒發現javaassist可以對字節碼進行操作和修改。此工具是JBOSS項目的一部分,JBOSS實現AOP的基礎。呵呵,開眼界了,原來我們可以直接對字節碼文件進行修改,哪怕不知道源文件(跟反編譯完全不同)。一個簡單例子:

          import javassist.*;
          class Hello {
          ??? public void say() {
          ??????? System.out.println("Hello");
          ??? }
          }

          public class Test {
          ??? public static void main(String[] args) throws Exception {
          ??????? ClassPool cp = ClassPool.getDefault();
          ??????? CtClass cc = cp.get("Hello");
          ??????? CtMethod m = cc.getDeclaredMethod("say");
          ??????? m.setBody("{System.out.println(/"shit/");}");
          ??????? m.insertBefore("System.out.println(/"fuck/");");
          ??????? Class c = cc.toClass();
          ??????? Hello h = (Hello)c.newInstance();
          ??????? h.say();
          ??? }
          }

          編譯運行此文件,輸出:

          fuck

          shit

          我們在

          ?CtMethod m = cc.getDeclaredMethod("say");
          ? m.setBody("{System.out.println(/"shit/");}");

          ? m.insertBefore("System.out.println(/"fuck/");");

          修改了say()方法,改成了

          System.out.println("fuck");

          System.out.println("shit");

          這里的ClassPool是CtClass的容器,它讀取class文件,并根據要求保存CtClass的結構以便日后使用,默認狀態下是從當前的類裝載器獲得,當然你可以指定:

          pool.insertClassPath("/usr/local/javalib");

          當然,不僅僅是修改方法,你還可以新建一個class,利用makeClass()方法,如:

          ClassPool pool = ClassPool.getDefault();
          CtClass cc = pool.makeClass("Point");

          還可以新增方法,下面是sample里的一個例子,同樣的:

          package sample;

          import javassist.*;
          import java.lang.reflect.*;

          /*
          ?? A very simple sample program

          ?? This program overwrites sample/Test.class (the class file of this
          ?? class itself) for adding a method g().? If the method g() is not
          ?? defined in class Test, then this program adds a copy of
          ?? f() to the class Test with name g().? Otherwise, this program does
          ?? not modify sample/Test.class at all.

          ?? To see the modified class definition, execute:

          ?? % javap sample.Test

          ?? after running this program.
          */
          public class Test {
          ??? public int f(int i) {
          ??? ?i++;
          ?? ?return i;
          ??? }

          ??? public static void main(String[] args) throws Exception {
          ?ClassPool pool = ClassPool.getDefault();

          ?CtClass cc = pool.get("sample.Test");
          ?Test test=new Test();
          ?Class c=test.getClass();
          ?Method []method=c.getDeclaredMethods();
          ?for(int i=0;i<method.length;i++){
          ??System.out.println(method[i]);
          ?}
          ?try {
          ???? cc.getDeclaredMethod("g");
          ???? System.out.println("g() is already defined in sample.Test.");
          ?}
          ?catch (NotFoundException e) {
          ???? /* getDeclaredMethod() throws an exception if g()
          ????? * is not defined in sample.Test.
          ????? */
          ???? CtMethod fMethod = cc.getDeclaredMethod("f");
          ???? CtMethod gMethod = CtNewMethod.copy(fMethod, "g", cc, null);
          ???? cc.addMethod(gMethod);
          ???? cc.writeFile();?// update the class file
          ???? System.out.println("g() was added.");
          ?}
          ??? }
          }
          第一次運行時,因為Test里并沒有g()方法,所以執行

          ?CtMethod fMethod = cc.getDeclaredMethod("f");
          ???? CtMethod gMethod = CtNewMethod.copy(fMethod, "g", cc, null);? //把f方法復制給g
          ???? cc.addMethod(gMethod);
          ???? cc.writeFile();?//更新class文件

          ???? System.out.println("g() was added.");
          打印:g() was added

          第2次運行時,因為以上步驟已經在class文件中增加了一個g方法,所以

          ?System.out.println("g() is already defined in sample.Test.");
          打印:g() is already defined in sample.Test

          ?

          Javassist不僅能修改你自己的class文件,而且可以同樣修改JDK自帶的類庫(廢話,類庫也是人寫的^_^)具體請看它的tutorial。

          主站蜘蛛池模板: 崇明县| 金门县| 永顺县| 游戏| 屏边| 兴宁市| 诸暨市| 诸城市| 东兰县| 桂东县| 富蕴县| 翁牛特旗| 景德镇市| 揭阳市| 远安县| 湖州市| 台南市| 花莲市| 洛浦县| 泾源县| 丹寨县| 巨野县| 方正县| 香格里拉县| 沿河| 陆河县| 同江市| 丹棱县| 晋州市| 宾川县| 怀宁县| 西贡区| 苍山县| 达日县| 二连浩特市| 邵阳市| 门源| 科尔| 灵丘县| 静乐县| 通化县|