Javaassist簡介

1、簡介

Javassist (JAVA programming ASSISTant) 是在 Java 中編輯字節(jié)碼的類庫;它使 Java 程序能夠在運行時定義一個新類, 并在 JVM 加載時修改類文件。

我們常用到的動態(tài)特性主要是反射,在運行時查找對象屬性、方法,修改作用域,通過方法名稱調用方法等。在線的應用不會頻繁使用反射,因為反射的性能開銷較大。其實還有一種和反射一樣強大的特性,但是開銷卻很低,它就是Javassit。

與其他類似的字節(jié)碼編輯器不同, Javassist 提供了兩個級別的 API: 源級別和字節(jié)碼級別。 如果用戶使用源級 API, 他們可以編輯類文件, 而不知道 Java 字節(jié)碼的規(guī)格。 整個 API 只用 Java 語言的詞匯來設計。 您甚至可以以源文本的形式指定插入的字節(jié)碼; Javassist 在運行中編譯它。 另一方面, 字節(jié)碼級 API 允許用戶直接編輯類文件作為其他編輯器。

2、讀取和寫入字節(jié)碼

類 Javassist.CtClass 是類文件的抽象表示形式。CtClass (編譯時類) 對象是處理類文件的句柄。下面的程序是一個非常簡單的示例:

ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Rectangle");
cc.setSuperclass(pool.get("test.Point"));
cc.writeFile();

該程序首先獲得一個 ClassPool 對象, 它通過 Javassist 控制字節(jié)碼修改。ClassPool 對象是表示類文件的 CtClass 對象的容器。它根據(jù)需要讀取類文件以構造 CtClass 對象, 并記錄構造對象以響應以后的訪問。若要修改類的定義, 用戶必須首先從 ClassPool 對象獲取對表示該類的 CtClass 對象的引用。ClassPool 中的 get() 用于此目的。如上所示的程序, 表示類測試的 CtClass 對象。矩形是從 ClassPool 對象獲得的, 它被分配給一個變量 cc。getDefault 返回的 ClassPool 對象搜索默認的系統(tǒng)搜索路徑。

可以修改從 ClassPool 對象獲得的 CtClass 對象 (稍后將介紹如何修改 CtClass 的詳細信息)。在上面的例子中, 它被修改以便測試的超類。將矩形更改為類測試點。當最終調用 CtClass () 中的 writeFile () 時, 此更改將反映在原始類文件中。
writeFile () 將 CtClass 對象轉換為類文件, 并將其寫入本地磁盤。Javassist 還提供了一種直接獲取修改后的字節(jié)碼的方法。要獲取字節(jié)碼, 請調用 toBytecode ():

byte[] b = cc.toBytecode();

您還可以直接加載 CtClass:

Class clazz = cc.toClass();

toClass() 請求當前線程的上下文類加載程序加載由 CtClass 表示的類文件。它返回一個表示已加載類的 java.lang.Class 對象。

2.1、定義類

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

此程序定義一個類 Point, 包括沒有成員??梢允褂?CtNewMethod 中聲明的工廠方法創(chuàng)建點的成員方法, 并在 CtClass 中追加到點與 addMethod ()。
makeClass () 無法創(chuàng)建新接口; 可以使用 makeInterface () 做。接口中的成員方法可以在 CtNewMethod 中使用 abstractMethod () 創(chuàng)建。請注意, 接口方法是一種抽象方法。

2.2、凍結類

如果 CtClass 對象由 writeFile ()、toClass () 或 toBytecode () 轉換為類文件, Javassist 將凍結該 CtClass 對象。那 CtClass 對象的進一步修改不被允許。這是為了在開發(fā)人員試圖修改已加載的類文件時發(fā)出警告, 因為 JVM 不允許重新加載類。
凍結的 CtClass 可以解凍, 以便允許對類定義進行修改。例如,

CtClasss cc = ...;
    :
cc.writeFile();
cc.defrost();
cc.setSuperclass(...);    // OK since the class is not frozen.

2.3、類搜索路徑

靜態(tài)方法 ClassPool.getDefault () 返回的默認 ClassPool 將搜索底層 JVM (Java 虛擬機) 具有的同一路徑。如果某個程序在 web 應用程序服務器 (如 JBoss 和 Tomcat) 上運行, 則 ClassPool 對象可能無法找到用戶類, 因為這樣的 web 應用程序服務器使用多個類加載器以及系統(tǒng)類加載程序。在這種情況下, 必須將附加的類路徑注冊到 ClassPool。假設池引用的是 ClassPool 對象:

pool.insertClassPath(new ClassClassPath(this.getClass()));

此語句注冊用于加載此引用的對象的類的類路徑??梢詫⑷魏晤悓ο笥米鲄?shù)而不是this.getClass ()。用于加載由該類對象表示的類的類路徑已注冊。
可以將目錄名注冊為類搜索路徑。例如, 下面的代碼將目錄/usr/local/javalib 添加到搜索路徑中:

ClassPool pool = ClassPool.getDefault();
pool.insertClassPath("/usr/local/javalib");

用戶可以添加的搜索路徑不僅是一個目錄, 而且可以是一個 URL:

ClassPool pool = ClassPool.getDefault();
ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist.");
pool.insertClassPath(cp);

此程序將 "http://www.javassist.org:80/java/" 添加到類搜索路徑中。此 URL 僅用于搜索屬于包組織 javassist 的類。例如, 要加載類 org.javassist.test.Main, 將從以下內容獲取其類文件:

http://www.javassist.org:80/java/org/javassist/test/Main.class

此外, 您可以直接給 ClassPool 對象一個字節(jié)數(shù)組, 并從該數(shù)組構造一個 CtClass 對象。為此, 請使用 ByteArrayClassPath。例如,

ClassPool cp = ClassPool.getDefault();
byte[] b = a byte array;
String name = class name;
cp.insertClassPath(new ByteArrayClassPath(name, b));
CtClass cc = cp.get(name);

獲得的 CtClass 對象表示由 b 指定的類文件定義的類。ClassPool 從給定的 ByteArrayClassPath 讀取類文件 (如果調用了get(), 并且給定的類名為 get() 等于名稱指定的類別。
如果您不知道該類的完全限定名, 則可以在 ClassPool 中使用 makeClass ():

ClassPool cp = ClassPool.getDefault();
InputStream ins = an input stream for reading a class file;
CtClass cc = cp.makeClass(ins);

makeClass () 從給定輸入流返回構造的 CtClass 對象。您可以使用 makeClass() 將類文件送到 ClassPool 對象。如果搜索路徑包含大 jar 文件, 這可能會提高性能。由于 ClassPool 對象根據(jù)需要讀取類文件, 因此它可能會反復搜索每個類文件的整個 jar 文件。makeClass () 可用于優(yōu)化此搜索。由 makeClass () 構造的 CtClass 保存在 ClassPool 對象中, 不再讀取類文件。

3、小結

本文簡要介紹了javaassist及其簡單用法。會有一些讀者好奇:它和AOP有什么關系和區(qū)別?舉個簡單的例子即可:CGLib是動態(tài)代理的經典類庫,其底層實現(xiàn)使用ASM,javaassist是類似ASM的東東。

4、參考文獻

  1. javassist
  2. Java動態(tài)編程初探——Javassist
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,814評論 25 708
  • 1 幾年前,我在某集團IT部門擔任技術員時,業(yè)務系有位同事我印象非常深刻,姑且叫她L小姐,L小姐在公司從事電話銷售...
    洪生鵬閱讀 2,081評論 5 17
  • 這個詞語想了很久,一直不愿意動筆。原因是,我對美國證券法不太了解,而且證券法枯燥,我也不愿意去了解。 怕啥來啥。最...
    魚子醬閱讀 8,530評論 1 6
  • 老公接了兒子回來,我提前下好了面條讓兒子加餐,也要是爸爸的長壽面,吃碗面,吹了蠟燭吃蛋糕。感賞全家的辛福愉...
    夜雨軒1991閱讀 105評論 1 2