這兩天看到Hibernate的代理部分,第一反應是底層使用了反射,針對用戶實體生成了代理類,後來反應過來了,反射沒有任何可以產生新類的能力,也就順理成章地找到了Javassist(下載地址)。
在網上搜索到的大部分教程,都是針對Javassist的API進行一番講解,但是最後,往往沒有一個加載過程,而筆者模仿這些教程進行類的加載時,加載到的結果都是原來的類,並沒有產生字節碼被修改的內容。
在經過一番探索後,筆者發現,網上的大部分教程中的最後一步,保存字節碼,使用的均是writeFile的無參數重載,在查看其函數結構後發現,它還有一個String類型的重載,由於在Eclipse下,字節碼儲存的根位置並不是”.//”而是”.//bin”,而writeFile的另一個重載很可能是指定字節碼根位置的參數,筆者進行一番更改後發現,果不其然。
下面將演示代碼分享出來:
這是筆者項目的結構:
Editable.java: package com.thrblock.javassist; public class Editable { public void showInfo(){ System.out.println("InfoDefault!"); } } Main.java: package com.thrblock.javassist;import java.io.IOException;import javassist.CannotCompileException;import javassist.ClassPool;import javassist.CtClass;import javassist.CtMethod;import javassist.CtNewMethod;import javassist.NotFoundException;public class Main {public static void main(String[] args) {ClassPool pool = ClassPool.getDefault();try{pool.insertClassPath(".//bin");//設置根路徑。 (這裡設置的根路徑顯然沒被writeFile使用) CtClass cc = pool.makeClass("com.thrblock.javassist.EditableChanged");//模擬Hibernate代理模式,我們創建一個新類cc.setSuperclass(pool.get("com.thrblock.javassist.Editable"));//設置其父類CtMethodcm = CtNewMethod.make("public void showInfo(){super.showInfo();System.out.println(/"CustomInsertHAHA!/");}",cc);//追加一個方法,注意它覆蓋了父類中的方法。 cc.addMethod(cm);cc.writeFile(".//bin");//這裡比較重要,空參的結果就是沒有保存到eclipse字節碼根路徑裡。 }catch (NotFoundException | CannotCompileException | IOException e) {e.printStackTrace();}try{Class<?> cl = Class.forName("com.thrblock.javassist.EditableChanged");//加載我們的新類Editableed = (Editable) cl.newInstance();//由於其繼承與Editable類,這里和Hibernate裡的load道理一樣。 ed.showInfo();//調用方法。 }catch (ClassNotFoundException | InstantiationException |IllegalAccessException e) {e.printStackTrace();}}}打印結果:
InfoDefault!
CustomInsertHAHA!
其他注意事項:
由於我們是生成了一個類,如果這個類名和原類名一樣,則會覆蓋class文件,但是如果修改之前該class已經被JVM裝入,則修改的部分不會生效,必須重啟JVM。
總結
以上就是本文關於Eclipse下Javassist正確使用方法代碼解析的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!