詳解Java Cglib動態(tài)代理
今天來介紹另一種更為強大的代理——Cglib動態(tài)代理。
什么是Cglib動態(tài)代理?
我們先回顧一下上一篇的jdk動態(tài)代理,jdk動態(tài)代理是通過接口來在運行時動態(tài)創(chuàng)建委托類的代理對象,但是跟靜態(tài)代理一樣有一個缺點,就是必須和委托類實現(xiàn)相同的接口,當(dāng)接口數(shù)量增加時,便需要增加代理類的數(shù)量才能滿足需求,而且如果委托類是別人寫的,而且沒有實現(xiàn)任何接口,那么jdk動態(tài)代理就有些力不從心了。
這時候Cglib動態(tài)代理就脫穎而出了,Cglib并不依賴接口,可以直接生成委托類的代理對象,而且可以代理委托類的任意非final修飾的public和protected方法,我們可以先來看一個栗子。
先定義一個Programmer類:
public class Programmer { private String name; public void setName(String name) { System.out.println('Setting Name.'); this.name = name; }public void code(){ System.out.println(name + ' is writing bugs.'); }}
然后定義一個代理類:
public class ProgrammerProxy implements MethodInterceptor { /** * 內(nèi)部持有委托類對象的引用 */ private Object target; /** * 創(chuàng)建代理類對象 */ public Programmer createProxy(Programmer object){ target = object; //創(chuàng)建Enhancer對象 Enhancer enhancer = new Enhancer(); //設(shè)置要代理的目標(biāo)類,以擴展功能 enhancer.setSuperclass(this.target.getClass()); //設(shè)置單一回調(diào)對象,在回調(diào)中攔截對目標(biāo)方法的調(diào)用 enhancer.setCallback(this); //設(shè)置類加載器 enhancer.setClassLoader(object.getClass().getClassLoader()); //創(chuàng)建代理對象 return (Programmer)enhancer.create(); } /** * 回調(diào)方法:在代理實例上攔截并處理目標(biāo)方法的調(diào)用,返回結(jié)果 * @param proxy 代理類 * @param method 被代理的方法 * @param params 該方法的參數(shù)數(shù)組 * @param methodProxy */ @Override public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable { //調(diào)用之前處理 doBefore(); //調(diào)用原方法 method.invoke(target,params); //調(diào)用之后處理 doAfter(); return null; } private void doAfter() { System.out.println('do after.'); } private void doBefore() { System.out.println('do before.'); }}
然后測試一下:
public class ProxyTest { @Test public void testCglibProxy(){ //創(chuàng)建一個Programmer對象 Programmer programmerA = new Programmer(); programmerA.setName('Frank'); //創(chuàng)建代理對象 Programmer programmerProxyA = new ProgrammerProxy().createProxy(programmerA); programmerProxyA.code(); //修改代理對象 programmerProxyA.setName('Wang'); programmerProxyA.code(); //修改委托類對象 programmerA.setName('Song'); programmerProxyA.code(); }}
輸出如下:
Setting Name.do before.Frank is writing bugs.do after.do before.Setting Name.do after.do before.Wang is writing bugs.do after.Setting Name.do before.Song is writing bugs.do after.
Cglib實現(xiàn)動態(tài)代理的步驟也不是很麻煩,先創(chuàng)建一個類實現(xiàn)MethodInterceptor接口,重寫intercept方法,在intercep中可以截獲委托類的所有非final修飾的public和protected方法,上例中,method.invoke(target,params);即為調(diào)用原對象的原方法,在代理類中保存了委托類對象的引用,這一點跟JDK動態(tài)代理是一樣的。在調(diào)用原方法前先調(diào)用了doBefore方法,調(diào)用之后還調(diào)用了doAfter方法,從而實現(xiàn)了代理功能。至于createProxy方法,也只是一個固定步驟,先創(chuàng)建Enhance對象,然后將委托類的一些屬性往里塞,然后調(diào)用create方法來動態(tài)生成代理對象。
在測試類中,為了更明顯的說明代理類與委托類的關(guān)系,分別用代理類對象programmerProxyA和委托類對象programmerA對name字段進行修改,可以產(chǎn)生一樣的效果。
下面來對比一下Cglib動態(tài)代理與JDK動態(tài)代理:
1.兩者都是動態(tài)代理,都是運行時動態(tài)生成代理對象。
2.JDK動態(tài)代理利用的是接口信息來實現(xiàn)的代理,委托類必須實現(xiàn)某個或者某些接口,而Cglib則是利用繼承關(guān)系,利用asm在運行時動態(tài)生成委托類的子類,從而實現(xiàn)對委托類的代理。因此不依賴接口。
3.Cglib由于是利用繼承關(guān)系來實現(xiàn)代理的,因此無法代理被final修飾的類以及被final修飾的方法。
4.Cglib一般來說效率要比JDK動態(tài)代理效率更高,可以實現(xiàn)的代理也更為強大。
當(dāng)然,具體情況具體分析,雖然Cglib比Jdk動態(tài)代理更強大,但并不一定各個地方都強行使用,有時候JDK動態(tài)代理相對來說更加簡單粗暴。
至此,本篇完結(jié),代理相關(guān)內(nèi)容講解完畢,歡迎大家繼續(xù)關(guān)注。
jar包下載地址:https://www.jb51.net/softs/570453.html
以上就是詳解Java Cglib動態(tài)代理的詳細(xì)內(nèi)容,更多關(guān)于Java Cglib動態(tài)代理的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. asp(vbscript)中自定義函數(shù)的默認(rèn)參數(shù)實現(xiàn)代碼2. Ajax實現(xiàn)表格中信息不刷新頁面進行更新數(shù)據(jù)3. jsp EL表達(dá)式詳解4. jsp中sitemesh修改tagRule技術(shù)分享5. JavaWeb Servlet中url-pattern的使用6. 爬取今日頭條Ajax請求7. 如何使用瀏覽器擴展篡改網(wǎng)頁中的JS 文件8. ASP基礎(chǔ)知識VBScript基本元素講解9. ASP刪除img標(biāo)簽的style屬性只保留src的正則函數(shù)10. JSP servlet實現(xiàn)文件上傳下載和刪除
