這兩天看到Hibernate的代理部分,第一反應(yīng)是底層使用了反射,針對用戶實體生成了代理類,后來反應(yīng)過來了,反射沒有任何可以產(chǎn)生新類的能力,也就順理成章地找到了Javassist。
在網(wǎng)上搜索到的大部分教程,都是針對Javassist的API進(jìn)行一番講解,但是最后,往往沒有一個加載過程,而筆者模仿這些教程進(jìn)行類的加載時,加載到的結(jié)果都是原來的類,并沒有產(chǎn)生字節(jié)碼被修改的內(nèi)容。
在經(jīng)過一番探索后,筆者發(fā)現(xiàn),網(wǎng)上的大部分教程中的最后一步,保存字節(jié)碼,使用的均是writeFile的無參數(shù)重載,在查看其函數(shù)結(jié)構(gòu)后發(fā)現(xiàn),它還有一個String類型的重載,由于在Eclipse下,字節(jié)碼儲存的根位置并不是”.\\”而是”.\\bin”,而writeFile的另一個重載很可能是指定字節(jié)碼根位置的參數(shù),筆者進(jìn)行一番更改后發(fā)現(xiàn),果不其然。
下面將演示代碼分享出來:
這是筆者項目的結(jié)構(gòu):
1
2
3
4
5
6
7
8
|
Editable.java: package com.thrblock.javassist; public class Editable { public void showInfo(){ System.out.println( "InfoDefault!" ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
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" ); //設(shè)置根路徑。(這里設(shè)置的根路徑顯然沒被writeFile使用) CtClass cc = pool.makeClass( "com.thrblock.javassist.EditableChanged" ); //模擬Hibernate代理模式,我們創(chuàng)建一個新類 cc.setSuperclass(pool.get( "com.thrblock.javassist.Editable" )); //設(shè)置其父類 CtMethodcm = CtNewMethod.make( "public void showInfo(){super.showInfo();System.out.println(\"CustomInsertHAHA!\");}" ,cc); //追加一個方法,注意它覆蓋了父類中的方法。 cc.addMethod(cm); cc.writeFile( ".\\bin" ); //這里比較重要,空參的結(jié)果就是沒有保存到eclipse字節(jié)碼根路徑里。 } 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(); //調(diào)用方法。 } catch (ClassNotFoundException | InstantiationException |IllegalAccessException e) { e.printStackTrace(); } } } |
打印結(jié)果:
InfoDefault!
CustomInsertHAHA!
其他注意事項:
由于我們是生成了一個類,如果這個類名和原類名一樣,則會覆蓋class文件,但是如果修改之前該class已經(jīng)被JVM裝入,則修改的部分不會生效,必須重啟JVM。
總結(jié)
以上就是本文關(guān)于Eclipse下Javassist正確使用方法代碼解析的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
原文鏈接:http://blog.csdn.net/shuzhe66/article/details/39319121