生活随笔
收集整理的這篇文章主要介紹了
动态代理proxy与CGLib的区别
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載自?動態代理proxy與CGLib的區別
昨天被人問及動態代理與CGlib的區別,趕緊回顧一下:
什么是代理?靜態代理與動態代理靜態代理實例JDK動態代理實例CGLib 簡介CGLib 與JDK動態代理的區別
? ? 代理模式是Java中常見的一種模式,英文名字叫走Proxy或者Surrogate,代理的本意是一個人代表另一個人,或者一個機構代表另一個機構,采取行動,因而,代理和現實生活中的中介有很大的類似,你買房子、賣房子,可以自己去操作,但是需要了解和買賣房產無關的細節,如契稅等,而找一個中介,則不用關心這些與買賣房產無直接關系的中間細節,只關心業務本身。
? ? ?因而,我們可以把代理模式的適用,總結為:代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等
? ?代理模式的用途,可以分為如下幾種:
? ? 1)遠程代理(Remote ):為遠程對象的invoke提供代理,典型的例子如RMI或者EJB,都會在本地生成一個遠程對象的stub。
? ? 2)虛擬代理(Virtual):如果需要創建一個資源消耗大的對象,則可以首先使用一個代理,使這個對象在需要時才真正創建。
? ? 3)Copy-On-Write 代理:把復制延遲到客戶端需要時才采取行動
? ? 4)保護(Protect)
? ? 5)Cache代理
? ?2.靜態代理與動態代理
代理分為靜態代理和動態代理
? ?按照代理創建的時期,可以分為動態代理和靜態代理:
?靜態代理:由程序員或者自動生成工具生成代理類,然后進行代理類的編譯和運行。在代理類、委托類運行之前,代理類已經以.class的格式存在。
?動態代理:在程序運行時,由反射機制動態創建而成。
?3.靜態代理實例
? ? 靜態代理實例:
? ? ?首先需要一個接口:
[java]?view plaincopy
package?net.battier.dao;???????????public?interface?Count?{????????????public?void?queryCount();??????????????public?void?updateCount();????}??
? 然后是委托類,也就是接口的真正實現類,內涵主要的業務邏輯:
[java]?view plaincopy
package?net.battier.dao.impl;????import?net.battier.dao.Count;???????????public?class?CountImpl?implements?Count?{????????@Override??????public?void?queryCount()?{??????????System.out.println("查看賬戶方法...");????????}????????@Override??????public?void?updateCount()?{??????????System.out.println("修改賬戶方法...");????????}????}??
? ?最后是代理類:
[java]?view plaincopy
CountProxy.java??package?net.battier.dao.impl;????import?net.battier.dao.Count;???????????public?class?CountProxy?implements?Count?{??????private?CountImpl?countImpl;??????????????????public?CountProxy(CountImpl?countImpl)?{??????????this.countImpl?=?countImpl;??????}????????@Override??????public?void?queryCount()?{??????????System.out.println("事務處理之前");????????????????????countImpl.queryCount();??????????System.out.println("事務處理之后");??????}????????@Override??????public?void?updateCount()?{??????????System.out.println("事務處理之前");????????????????????countImpl.updateCount();??????????System.out.println("事務處理之后");????????}????}??
運行:
[java]?view plaincopy
package?com.mahoutchina.pattern.proxy;????public?class?CountTest?{????????????????public?static?void?main(String[]?args)?{??????????CountImpl?countImpl?=?new?CountImpl();????????????CountProxy?countProxy?=?new?CountProxy(countImpl);????????????countProxy.updateCount();????????????countProxy.queryCount();?????????}????}??
? 從靜態代理中可以看出:
? ? 1.接口:代理類需要實現一個接口,這個接口和委托類的接口是一樣的,這樣proxy才能和委托類行為表現一致
? ? 2. 方法(Method):由于接口限制,proxy類中也要有interface中的各個方法,這就造成了代碼重復
? ?
4.JDK動態代理實例
? ??動態代理類克服了proxy需要繼承專一的interface接口,并且要實現相應的method的缺陷。從JDK 1.3以來,Java 語言通過java.lang.reflex庫提供的三個類直接支持代理:
? ? ?java.lang.reflect.Proxy,java.lang.reflect.InvocationHandler 和Method.
? ? Proxy類在運行時動態創建代理對象,這也是dynamic proxy的由來,下面是類圖,其中最重要的是newProxyInstance,這個方法中,指明了將要代理的類的加載器,業務類接口,以及代理類要執行動作的調用處理器(InvokeHandler)
?
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,?
InvocationHandler h)?
?????????????????????????????? throws IllegalArgumentException?
參數說明:?
ClassLoader loader:類加載器?
Class<?>[] interfaces:得到全部的接口?
InvocationHandler h:得到InvocationHandler接口的子類實例?
Ps:類加載器?
在Proxy類中的newProxyInstance()方法中需要一個ClassLoader類的實例,ClassLoader實際上對應的是類加載器,在Java中主要有一下三種類加載器;?
Booststrap ClassLoader:此加載器采用C++編寫,一般開發中是看不到的;?
Extendsion ClassLoader:用來進行擴展類的加載,一般對應的是jre\lib\ext目錄中的類;?
AppClassLoader:(默認)加載classpath指定的類,是最常使用的是一種加載器。?
? ?當系統有了一個代理對象之后,對原方法的調用會首先被分派到一個調用處理器(Invocation Handler).InvocationHandler 接口如下圖所示:
? ??
? 代碼:
? ? 接口:
[java]?view plaincopy
package?com.mahoutchina.pattern.proxy.dynamicproxy;????public?interface?BookFacade?{??????public?void?addBook();??????public?void?deleteBook();??}??
? 實際業務類:
[java]?view plaincopy
package?com.mahoutchina.pattern.proxy.dynamicproxy;????public?class?BookFacadeImpl?implements?BookFacade?{????????@Override??????public?void?addBook()?{??????????System.out.println("add?book?logic?is?running。。。");???????}????????@Override??????public?void?deleteBook()?{??????????System.out.println("delete?book?logic?is?running。。。");????????????????}??????????}??
? 動態代理類:
[java]?view plaincopy
package?com.mahoutchina.pattern.proxy.dynamicproxy;????import?java.lang.reflect.InvocationHandler;??import?java.lang.reflect.Method;??import?java.lang.reflect.Proxy;????public?class?BookFacadeProxy?implements?InvocationHandler?{??????private?Object?target;??????????????????public?Object?bind(Object?target)?{??????????this.target?=?target;????????????????????return?Proxy.newProxyInstance(target.getClass().getClassLoader(),??????????????????target.getClass().getInterfaces(),?this);??????}????????@Override??????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)??????????????throws?Throwable?{??????????Object?result=null;??????????System.out.println("Proxy?start...");??????????System.out.println("method?name:"+method.getName());??????????result=method.invoke(target,?args);??????????System.out.println("Proxy?end...");??????????return?result;??????}????}??
? 測試類:
[java]?view plaincopy
package?com.mahoutchina.pattern.proxy.dynamicproxy;????ublic?class?TestProxy?{????????public?static?void?main(String[]?args)?{??????BookFacadeProxy?proxy?=?new?BookFacadeProxy();??????BookFacade?bookProxy?=?(BookFacade)?proxy.bind(new?BookFacadeImpl());??????bookProxy.addBook();??????bookProxy.deleteBook();??}??
??
?對于JDK 的Proxy,有以下幾點:
? ? 1)Interface:對于JDK proxy,業務類是需要一個Interface的,這也是一個缺陷
? ? 2)Proxy,Proxy 類是動態產生的,這個類在調用Proxy.newProxyInstance(targetCls.getClassLoader, targetCls.getInterface,InvocationHander)之后,會產生一個Proxy類的實例。實際上這個Proxy類也是存在的,不僅僅是類的實例。這個Proxy類可以保存到硬盤上。
? ? 3) Method:對于業務委托類的每個方法,現在Proxy類里面都不用靜態顯示出來
? ? 4) InvocationHandler: 這個類在業務委托類執行時,會先調用invoke方法。invoke方法再執行相應的代理操作,可以實現對業務方法的再包裝
? ? 5?CGLib 簡介
? ? ? ? ??JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。?
示例?
? ?業務類:
[java]?view plaincopy
package?net.battier.dao;????public?interface?BookFacade?{??????public?void?addBook();??}??
?
?
[java]?view plaincopy
package?net.battier.dao.impl;???????????public?class?BookFacadeImpl1?{??????public?void?addBook()?{??????????System.out.println("增加圖書的普通方法...");??????}??}??
? 代理:
[java]?view plaincopy
package?net.battier.proxy;????import?java.lang.reflect.Method;????import?net.sf.cglib.proxy.Enhancer;??import?net.sf.cglib.proxy.MethodInterceptor;??import?net.sf.cglib.proxy.MethodProxy;???????????public?class?BookFacadeCglib?implements?MethodInterceptor?{??????private?Object?target;???????????????????public?Object?getInstance(Object?target)?{??????????this.target?=?target;??????????Enhancer?enhancer?=?new?Enhancer();??????????enhancer.setSuperclass(this.target.getClass());????????????????????enhancer.setCallback(this);????????????????????return?enhancer.create();??????}????????@Override????????????public?Object?intercept(Object?obj,?Method?method,?Object[]?args,??????????????MethodProxy?proxy)?throws?Throwable?{??????????System.out.println("事物開始");??????????proxy.invokeSuper(obj,?args);??????????System.out.println("事物結束");??????????return?null;??????????}????}??
? 測試;
[java]?view plaincopy
package?net.battier.test;????import?net.battier.dao.impl.BookFacadeImpl1;??import?net.battier.proxy.BookFacadeCglib;????public?class?TestCglib?{????????????public?static?void?main(String[]?args)?{??????????BookFacadeCglib?cglib=new?BookFacadeCglib();??????????BookFacadeImpl1?bookCglib=(BookFacadeImpl1)cglib.getInstance(new?BookFacadeImpl1());??????????bookCglib.addBook();??????}??}??
總結
以上是生活随笔為你收集整理的动态代理proxy与CGLib的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。