生活随笔
收集整理的這篇文章主要介紹了
java动态代理(JDK和cglib)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
JAVA的動態代理?
代理模式?
代理模式是常用的java設計模式,他的特征是代理類與委托類有同樣的接口,代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的對象本身并不真正實現服務,而是通過調用委托類的對象的相關方法,來提供特定的服務。?
按照代理的創建時期,代理類可以分為兩種。?
靜態代理:由程序員創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。?
動態代理:在程序運行時,運用反射機制動態創建而成。?
?
首先看一下靜態代理:?
1、Count.java?
Java代碼?
package?net.battier.dao;????/**??*?定義一個賬戶接口??*???*?@author?Administrator??*???*/??public?interface?Count?{??????//?查看賬戶方法??????public?void?queryCount();????????//?修改賬戶方法??????public?void?updateCount();????}??
2、CountImpl.java?
Java代碼?
package?net.battier.dao.impl;????import?net.battier.dao.Count;????/**??*?委托類(包含業務邏輯)??*???*?@author?Administrator??*???*/??public?class?CountImpl?implements?Count?{????????@Override??????public?void?queryCount()?{??????????System.out.println("查看賬戶方法...");????????}????????@Override??????public?void?updateCount()?{??????????System.out.println("修改賬戶方法...");????????}????}????、CountProxy.java??package?net.battier.dao.impl;????import?net.battier.dao.Count;????/**??*?這是一個代理類(增強CountImpl實現類)??*???*?@author?Administrator??*???*/??public?class?CountProxy?implements?Count?{??????private?CountImpl?countImpl;????????/**??????*?覆蓋默認構造器??????*???????*?@param?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("事務處理之后");????????}????}?? ?
3、TestCount.java?
Java代碼?
package?net.battier.test;????import?net.battier.dao.impl.CountImpl;??import?net.battier.dao.impl.CountProxy;????/**??*測試Count類??*???*?@author?Administrator??*???*/??public?class?TestCount?{??????public?static?void?main(String[]?args)?{??????????CountImpl?countImpl?=?new?CountImpl();??????????CountProxy?countProxy?=?new?CountProxy(countImpl);??????????countProxy.updateCount();??????????countProxy.queryCount();????????}??}?? ?
觀察代碼可以發現每一個代理類只能為一個接口服務,這樣一來程序開發中必然會產生過多的代理,而且,所有的代理操作除了調用的方法不一樣之外,其他的操作都一樣,則此時肯定是重復代碼。解決這一問題最好的做法是可以通過一個代理類完成全部的代理功能,那么此時就必須使用動態代理完成。?
再來看一下動態代理:?
JDK動態代理中包含一個類和一個接口:?
InvocationHandler接口:?
public interface InvocationHandler {?
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;?
}?
參數說明:?
Object proxy:指被代理的對象。?
Method method:要調用的方法?
Object[] args:方法調用時所需要的參數?
可以將InvocationHandler接口的子類想象成一個代理的最終操作類,替換掉ProxySubject。?
Proxy類:?
Proxy類是專門完成代理的操作類,可以通過此類為一個或多個接口動態地生成實現類,此類提供了如下的操作方法:?
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指定的類,是最常使用的是一種加載器。?
動態代理?
與靜態代理類對照的是動態代理類,動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不僅簡化了編程工作,而且提高了軟件系統的可擴展性,因為Java 反射機制可以生成任意類型的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。?
動態代理示例:?
1、BookFacade.java?
Java代碼?
package?net.battier.dao;????public?interface?BookFacade?{??????public?void?addBook();??}?? ?
2、BookFacadeImpl.java?
Java代碼?
package?net.battier.dao.impl;????import?net.battier.dao.BookFacade;????public?class?BookFacadeImpl?implements?BookFacade?{????????@Override??????public?void?addBook()?{??????????System.out.println("增加圖書方法。。。");??????}????}????、BookFacadeProxy.java????package?net.battier.proxy;????import?java.lang.reflect.InvocationHandler;??import?java.lang.reflect.Method;??import?java.lang.reflect.Proxy;????/**??*?JDK動態代理代理類??*???*?@author?student??*???*/??public?class?BookFacadeProxy?implements?InvocationHandler?{??????private?Object?target;??????/**??????*?綁定委托對象并返回一個代理類??????*?@param?target??????*?@return??????*/??????public?Object?bind(Object?target)?{??????????this.target?=?target;??????????//取得代理對象??????????return?Proxy.newProxyInstance(target.getClass().getClassLoader(),??????????????????target.getClass().getInterfaces(),?this);???//要綁定接口(這是一個缺陷,cglib彌補了這一缺陷)??????}????????@Override??????/**??????*?調用方法??????*/??????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)??????????????throws?Throwable?{??????????Object?result=null;??????????System.out.println("事物開始");??????????//執行方法??????????result=method.invoke(target,?args);??????????System.out.println("事物結束");??????????return?result;??????}????}?? ?
3、TestProxy.java?
Java代碼?
package?net.battier.test;????import?net.battier.dao.BookFacade;??import?net.battier.dao.impl.BookFacadeImpl;??import?net.battier.proxy.BookFacadeProxy;????public?class?TestProxy?{????????public?static?void?main(String[]?args)?{??????????BookFacadeProxy?proxy?=?new?BookFacadeProxy();??????????BookFacade?bookProxy?=?(BookFacade)?proxy.bind(new?BookFacadeImpl());??????????bookProxy.addBook();??????}????}?? ?
但是,JDK的動態代理依靠接口實現,如果有些類并沒有實現接口,則不能使用JDK代理,這就要使用cglib動態代理了。?
Cglib動態代理?
JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,并覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。?
示例?
1、BookFacadeCglib.java?
Java代碼?
package?net.battier.dao;????public?interface?BookFacade?{??????public?void?addBook();??}?? ?
2、BookCadeImpl1.java?
Java代碼?
package?net.battier.dao.impl;????/**??*?這個是沒有實現接口的實現類??*???*?@author?student??*???*/??public?class?BookFacadeImpl1?{??????public?void?addBook()?{??????????System.out.println("增加圖書的普通方法...");??????}??}??
3、BookFacadeProxy.java?
Java代碼?
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;????/**??*?使用cglib動態代理??*???*?@author?student??*???*/??public?class?BookFacadeCglib?implements?MethodInterceptor?{??????private?Object?target;????????/**??????*?創建代理對象??????*???????*?@param?target??????*?@return??????*/??????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;??????????}????}??
4、TestCglib.java?
Java代碼?
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();??????}??} ?
轉載于:https://my.oschina.net/huluobotx/blog/501527
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的java动态代理(JDK和cglib)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。