日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用javassist动态注入代码

發布時間:2024/4/17 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用javassist动态注入代码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://dennis-zane.iteye.com/blog/57540

?

關于java字節碼的處理,目前有很多工具,如bcel,asm。不過這些都需要直接跟虛擬機指令打交道。如果你不想了解虛擬機指令,可以采用javassist。javassist是jboss的一個子項目,其主要的優點,在于簡單,而且快速。直接使用java編碼的形式,而不需要了解虛擬機指令,就能動態改變類的結構,或者動態生成類。
??? 下面通過一個簡單的例子,通過javassist來實現如何動態注入代碼。
??? 假設,存在類A,如下:
public class A {
??? public void method() {
??????? for (int i = 0; i < 1000000; i++) {
??????? }
??????? System.out.println("method1");
??? }
}
測試類B如下:
public class B {
??? public static void main(String[] args) {
??????? A a = new A();
??????? a.method();?? ?
??? }
}
現在想統計一下method的執行時間,
默認的實現是修改method:
?public void method() {
??????? long start = System.currentTimeMillis();
??????? for (int i = 0; i < 1000000; i++) {
??????? }
??????? System.out.println("method1");
??????? long end = System.currentTimeMillis();
??????? System.out.println(end - start);
??? }
如果A的方法很多,統計方法的執行時間的代碼就會相應的增加。為了減少工作量,通過動態注入代碼的形式來實現。
修改B的main方法:
??? public static void main(String[] args) throws Exception {
?? ?? //用于取得字節碼類,必須在當前的classpath中,使用全稱
??????? CtClass ctClass = ClassPool.getDefault().get("org.esoft.A");
???????? //需要修改的方法名稱
??????? String mname = "method";?????? ?
??????? CtMethod mold = ctClass.getDeclaredMethod(mname);
???????? //修改原有的方法名稱
??????? String nname = mname + "$impl";
??????? mold.setName(nname);
???????? //創建新的方法,復制原來的方法
??????? CtMethod mnew = CtNewMethod.copy(mold, mname, ctClass, null);
???????? //主要的注入代碼
??????? StringBuffer body = new StringBuffer();
??????? body.append("{\nlong start = System.currentTimeMillis();\n");
??????? //調用原有代碼,類似于method();($$)表示所有的參數
??????? body.append(nname + "($$);\n");
??????? body.append("System.out.println(\"Call to method "
??????????????????? + mname
??????????????????? + " took \" +\n (System.currentTimeMillis()-start) + "
??????????????????? + "\" ms.\");\n");
????? ?
??????? body.append("}");
???????? //替換新方法
??????? mnew.setBody(body.toString());
???????? //增加新方法
??????? ctClass.addMethod(mnew);
??????? //類已經更改,注意不能使用A a=new A();,因為在同一個classloader中,不允許裝載同一個類兩次
??????? A a=(A)ctClass.toClass().newInstance();
??????? a.method();
??? }
這只是簡單的一個應用。javassist還提供了很多的功能,用于更改類結構。有興趣的可以參考相關文檔

?

==============

http://dennis-zane.iteye.com/blog/57540

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

  • 博客分類:
  • java
JBossAOPCC++C#?

最近重新再看<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(/"/");}");
??????? m.insertBefore("System.out.println(/"/");");
??????? Class c = cc.toClass();
??????? Hello h = (Hello)c.newInstance();
??????? h.say();
??? }
}

編譯運行此文件,輸出:

我們在

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

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

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

System.out.println("");

System.out.println("");

這里的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。

總結

以上是生活随笔為你收集整理的使用javassist动态注入代码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。