生活随笔
收集整理的這篇文章主要介紹了
JAVA设计模式-11-代理模式(动态)(一)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
java的動態(tài)代理機制詳解 代理模式原理及實例講解 代理模式詳解包含原理詳解 Java動態(tài)代理的實現(xiàn) JAVA學習篇--靜態(tài)代理VS動態(tài)代理 深入理解Java Proxy機制
一、什么是動態(tài)代理
在靜態(tài)代理(Static Proxy)模式中,代理類都是真實存在的,由程序員提前創(chuàng)建好的java類,是靜態(tài)的,每一個代理類在編譯之后都會生成一個.class字節(jié)碼文件,靜態(tài)代理類所實現(xiàn)的接口和所代理的方法早在編譯期都已被固定了。
動態(tài)代理(Dynamic Proxy)則不同:動態(tài)代理使用字節(jié)碼動態(tài)生成和加載技術(shù),在系統(tǒng)運行時動態(tài)地生成和加載代理類。
與靜態(tài)代理相比,動態(tài)代理有以下優(yōu)點:首先,無需再為每一個真實主題寫一個形式上完全一樣的代理類,假如抽象主題接口中的方法很多的話,為每一個接口方法寫一個代理方法也很麻煩,同樣地,如果后期抽象主題接口發(fā)生變動,則真實主題和代理類都要修改,不利于系統(tǒng)維護;其次,動態(tài)代理可以讓系統(tǒng)根據(jù)實際需要來動態(tài)創(chuàng)建代理類,同一個代理類能夠代理多個不同的真實主題類,并且可以代理多個不同的方法。
二、Java對動態(tài)代理的支持
從JDK 1.3版本開始,Java語言提供了對動態(tài)代理的支持,在Java中實現(xiàn)動態(tài)代理機制,需要用到 java.lang.reflect 包中的 InvocationHandler 接口和 Proxy 類,我們先來看看java的API幫助文檔是怎么樣對這兩個類進行描述的:
InvocationHandler
[html]?view plaincopy
InvocationHandler?is?the?interface?implemented?by?the?invocation?handler?of?a?proxy?instance.??? Each?proxy?instance?has?an?associated?invocation?handler.?When?a?method?is?invoked?on?a?proxy?instance,?the??? method?invocation?is?encoded?and?dispatched?to?the?invoke?method?of?its?invocation?handler.?? [html]?view plaincopy
InvocationHandler?是代理實例的調(diào)用處理程序?qū)崿F(xiàn)的接口。?? 每個代理實例都具有一個與之關(guān)聯(lián)的調(diào)用處理程序。對代理實例調(diào)用方法時,將對方法調(diào)用進行編碼并將其指派到它的調(diào)用處理程?? 序的?invoke()?方法。?? invoke() 方法形式如下: [java]?view plaincopy
Object?invoke(Object?proxy,?? Method?method,?? Object[]?args)?? throws?Throwable?? InvocationHandler 接口只包含invoke()這唯一一個方法,該方法用于處理對代理類實例的方法調(diào)用并返回相應的結(jié)果,當一個代理實例中的業(yè)務方法被調(diào)用時將自動調(diào)用該方法。invoke()方法包含三個參數(shù),其中第一個參數(shù)proxy表示代理類的實例,第二個參數(shù)method表示需要代理的方法,第三個參數(shù)args表示代理方法的參數(shù)數(shù)組。
Proxy?
[html]?view plaincopy
Proxy?provides?static?methods?for?creating?dynamic?proxy?classes?and?instances,?and?it?is?also?the?superclass??? of?all?dynamic?proxy?classes?created?by?those?methods.??? [html]?view plaincopy
Proxy?提供用于創(chuàng)建動態(tài)代理類和實例的靜態(tài)方法,它還是由這些方法創(chuàng)建的所有動態(tài)代理類的超類。?? Proxy提供給我們的靜態(tài)方法有以下四個: [html]?view plaincopy
//返回指定代理實例的調(diào)用處理程序。?? static?InvocationHandler?getInvocationHandler(Object?proxy)??? //返回代理類的?java.lang.Class?對象,并向其提供類加載器和接口數(shù)組。?? static?Class<?><span?style="white-space:pre">???</span>getProxyClass(ClassLoader?loader,?Class<?>[]?interfaces)??? //當且僅當指定的類通過?getProxyClass?方法或?newProxyInstance?方法動態(tài)生成為代理類時,返回?true。?? static?boolean<span?style="white-space:pre">??</span>isProxyClass(Class<?>?cl)??? ?? //返回一個指定接口的代理類實例,該接口可以將方法調(diào)用指派到指定的調(diào)用處理程序。?? //方法中的?ClassLoader?loader?參數(shù)用來指定動態(tài)代理類的類加載器,Class<?>[]?interfaces用來指定動態(tài)代理類要實現(xiàn)的接口。?? //InvocationHandler?h?用來指定與即將生成的動態(tài)代理對象相關(guān)聯(lián)的調(diào)用處理程序?? static?Object<span?style="white-space:pre">???</span>newProxyInstance(ClassLoader?loader,?Class<?>[]?interfaces,?InvocationHandler?h)??? 下面我們以為數(shù)據(jù)庫增加日志記錄功能(為簡單起見,我們僅記錄下所有操作的執(zhí)行時間及操作執(zhí)行的結(jié)果)為例來看一看如何使用這兩個類實現(xiàn)動態(tài)代理:
為了使演示更清晰,在此先定義兩個簡單類,一個User類和一個Document類分別表示數(shù)據(jù)庫中的用戶記錄和文檔記錄,其代碼如下。
[java]?view plaincopy
public?class?User?{?? ??? ?private?Long?id;?? ??? ?private?String?name;?? ?public?User(Long?id,?String?name)?{?? ??super();?? ??this.id?=?id;?? ??this.name?=?name;?? ?}?? ?public?Long?getId()?{?? ??return?id;?? ?}?? ?public?void?setId(Long?id)?{?? ??this.id?=?id;?? ?}?? ?public?String?getName()?{?? ??return?name;?? ?}?? ?public?void?setName(String?name)?{?? ??this.name?=?name;?? ?}?? }?? [java]?view plaincopy
public?class?Document?{?? ??? ?private?Long?id;?? ??? ?private?String?title;?? ?public?Document(Long?id,?String?title)?{?? ??super();?? ??this.id?=?id;?? ??this.title?=?title;?? ?}?? ?public?Long?getId()?{?? ??return?id;?? ?}?? ?public?void?setId(Long?id)?{?? ??this.id?=?id;?? ?}?? ?public?String?getTitle()?{?? ??return?title;?? ?}?? ?public?void?setTitle(String?title)?{?? ??this.title?=?title;?? ?}?? }?? 另外還需定義一個DataBase類用來扮演數(shù)據(jù)庫的功能,在此為簡單起見,將數(shù)據(jù)庫中的用戶記錄和文檔記錄分別存儲在一個Map中,代碼如下。
[java]?view plaincopy
import?java.util.HashMap;?? import?java.util.Map;?? public?class?DataBase?{?? ?private?static?Map<Long,?User>?userMap?=?null;?? ?private?static?Map<Long,?Document>?documentMap?=?null;?? ??? ?private?static?User?currentUser?=?null;?? ?private?DataBase()?{?? ???? ??userMap?=?new?HashMap<Long,?User>();?? ??userMap.put(20160708L,?new?User(20160708L,?"燕凌嬌"));?? ??userMap.put(20160709L,?new?User(20160709L,?"姬如雪"));?? ??userMap.put(20160710L,?new?User(20160710L,?"百里登風"));?? ???? ??documentMap?=?new?HashMap<Long,?Document>();?? ??documentMap.put(30160708L,?new?Document(30160708L,?"C++常用算法手冊"));?? ??documentMap?? ????.put(30160709L,?new?Document(30160709L,?"深入理解Android內(nèi)核設計思想"));?? ??documentMap.put(30160710L,?new?Document(30160710L,?"Java從入門到放棄"));?? ?}?? ?public?User?getCurrentUser()?{?? ??return?currentUser;?? ?}?? ?public?void?setCurrentUser(User?currentUser)?{?? ??DataBase.currentUser?=?currentUser;?? ?}?? ?public?Map<Long,?User>?getUserMap()?{?? ??return?userMap;?? ?}?? ?public?Map<Long,?Document>?getDocumentMap()?{?? ??return?documentMap;?? ?}?? ?public?static?DataBase?getDataBaseInstance()?{?? ??return?DataBaseHolder.dataBase;?? ?}?? ?public?static?class?DataBaseHolder?{?? ??private?static?DataBase?dataBase?=?new?DataBase();?? ?}?? }?? 數(shù)據(jù)庫布置完成了,接下來開始寫動態(tài)代理相關(guān)代碼了,為了與靜態(tài)代理進行比較,在此我們來創(chuàng)建兩個接口(抽象主題角色)。
[java]?view plaincopy
public?interface?UserDao?{?? ??? ?String?login(Long?id);?? ??? ?String?logout();?? }?? [java]?view plaincopy
public?interface?DocumentDao?{?? ??? ?String?add(Document?document);?? ??? ?String?delete(Document?document);?? }?? 接下來是兩個真實主題角色,ImpUserDao 類和ImpDocumentDao類,為了使示例結(jié)果清晰,此處將接口的執(zhí)行結(jié)果直接以字符串形式返回。
[java]?view plaincopy
public?class?ImpUserDao?implements?UserDao?{?? ?@Override?? ?public?String?login(Long?id)?{?? ??User?user?=?DataBase.getDataBaseInstance().getUserMap().get(id);?? ??if?(null?!=?user)?{?? ????? ???DataBase.getDataBaseInstance().setCurrentUser(user);?? ???return?"用戶["?+?user.getName()?+?"]登陸成功...";?? ??}?else?{?? ????? ???return?"登陸失敗,ID為\""?+?id?+?"\"的用戶不存在!";?? ??}?? ?}?? ?@Override?? ?public?String?logout()?{?? ??User?user?=?DataBase.getDataBaseInstance().getCurrentUser();?? ??if?(null?!=?user)?{?? ????? ???DataBase.getDataBaseInstance().setCurrentUser(null);?? ???return?"用戶["?+?user.getName()?+?"]退出登陸成功...";?? ??}?else?{?? ????? ???return?"退出登陸失敗,當前無登陸用戶!";?? ??}?? ?}?? }?? [java]?view plaincopy
public?class?ImpDocumentDao?implements?DocumentDao?{?? ?@Override?? ?public?String?add(Document?document)?{?? ??User?user?=?DataBase.getDataBaseInstance().getCurrentUser();?? ??if?(null?==?user)?{?? ????? ???return?"保存失敗,未獲取到登陸信息!";?? ??}?else?{?? ???Document?dbDocument?=?DataBase.getDataBaseInstance()?? ?????.getDocumentMap().get(document.getId());?? ???if?(null?!=?dbDocument)?{?? ?????? ????return?"添加文檔《"?+?document.getTitle()?+?"》失敗,文檔已存在!";?? ???}?else?{?? ?????? ????DataBase.getDataBaseInstance().getDocumentMap()?? ??????.put(document.getId(),?document);?? ????return?"添加文檔《"?+?document.getTitle()?+?"》成功...";?? ???}?? ??}?? ?}?? ?@Override?? ?public?String?delete(Document?document)?{?? ??User?user?=?DataBase.getDataBaseInstance().getCurrentUser();?? ??if?(null?==?user)?{?? ????? ???return?"保存失敗,未獲取到登陸信息!";?? ??}?else?{?? ???Document?dbDocument?=?DataBase.getDataBaseInstance()?? ?????.getDocumentMap().get(document.getId());?? ???if?(null?==?dbDocument)?{?? ?????? ????return?"刪除文檔《"?+?document.getTitle()?+?"》失敗,文檔不存在!";?? ???}?else?{?? ?????? ????DataBase.getDataBaseInstance().getDocumentMap()?? ??????.remove(document.getId());?? ????return?"刪除文檔《"?+?document.getTitle()?+?"》成功...";?? ???}?? ??}?? ?}?? }?? 最后,我們就要定義動態(tài)代理類了,前面說過,每一個動態(tài)代理類都必須要實現(xiàn) InvocationHandler 這個接口,因此我們這個動態(tài)代理類也不例外。
[java]?view plaincopy
import?java.lang.reflect.InvocationHandler;?? import?java.lang.reflect.Method;?? import?java.util.Calendar;?? import?java.util.GregorianCalendar;?? public?class?DataBaseLogHandler?implements?InvocationHandler?{?? ?private?Object?object;?? ?private?Calendar?calendar;?? ?public?DataBaseLogHandler(Object?object)?{?? ??super();?? ??this.object?=?object;?? ?}?? ??? ?@Override?? ?public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?? ???throws?Throwable?{?? ??before(method);?? ?????? ??Object?result?=?method.invoke(object,?args);??? ??after(result);?? ??if?(method.getName().equalsIgnoreCase("logout"))?{?? ???System.out.println("**********************************");?? ???System.out.println("");?? ??}?? ??return?result;?? ?}?? ?public?void?before(Method?method)?{?? ??calendar?=?new?GregorianCalendar();?? ??int?year?=?calendar.get(Calendar.YEAR);?? ??int?month?=?calendar.get(Calendar.MONTH);?? ??int?date?=?calendar.get(Calendar.DATE);?? ??int?hour?=?calendar.get(Calendar.HOUR_OF_DAY);?? ??int?minute?=?calendar.get(Calendar.MINUTE);?? ??int?second?=?calendar.get(Calendar.SECOND);?? ??String?time?=?hour?+?"時"?+?minute?+?"分"?+?second?+?"秒";?? ??System.out.println("北京時間:"?+?year?+?"年"?+?month?+?"月"?+?date?+?"日"?? ????+?time?+?",執(zhí)行方法\""?+?method.getName()?+?"\"");?? ?}?? ?public?void?after(Object?object)?{?? ??System.out.println("執(zhí)行結(jié)果:"?+?object);?? ?}?? }?? 至此,動態(tài)代理所需要的類就算創(chuàng)建完成了,接下來創(chuàng)建一個Client充當客戶端來測試一下。
[java]?view plaincopy
import?java.lang.reflect.Proxy;?? public?class?Client{?? ?public?static?void?main(String[]?args)?{?? ????? ??UserDao?userDao?=?new?ImpUserDao();?? ??DataBaseLogHandler?userHandler?=?new?DataBaseLogHandler(userDao);?? ??DocumentDao?doucumentDao?=?new?ImpDocumentDao();?? ??DataBaseLogHandler?documentHandler?=?new?DataBaseLogHandler(?? ????doucumentDao);?? ??UserDao?userProxy?=?(UserDao)?Proxy.newProxyInstance(?? ????UserDao.class.getClassLoader(),?new?Class[]?{?UserDao.class?},?? ????userHandler);?? ??DocumentDao?documentProxy?=?(DocumentDao)?Proxy.newProxyInstance(?? ????DocumentDao.class.getClassLoader(),?? ????new?Class[]?{?DocumentDao.class?},?documentHandler);?? ???? ??userProxy.login(20160718L);?? ??documentProxy.add(new?Document(30160711L,?"轉(zhuǎn)角遇見幸福"));?? ??userProxy.logout();?? ???? ??userProxy.login(20160708L);?? ??documentProxy.add(new?Document(30160711L,?"轉(zhuǎn)角遇見幸福"));?? ??documentProxy.add(new?Document(30160711L,?"轉(zhuǎn)角遇見幸福"));?? ??userProxy.logout();?? ?}?? }?? 運行程序打印結(jié)果如下:
[html]?view plaincopy
北京時間:2016年6月11日19時33分46秒,執(zhí)行方法"login"?? 執(zhí)行結(jié)果:登陸失敗,ID為"20160718"的用戶不存在!?? 北京時間:2016年6月11日19時33分46秒,執(zhí)行方法"add"?? 執(zhí)行結(jié)果:保存失敗,未獲取到登陸信息!?? 北京時間:2016年6月11日19時33分46秒,執(zhí)行方法"logout"?? 執(zhí)行結(jié)果:退出登陸失敗,當前無登陸用戶!?? **********************************?? ?? 北京時間:2016年6月11日19時33分46秒,執(zhí)行方法"login"?? 執(zhí)行結(jié)果:用戶[燕凌嬌]登陸成功...?? 北京時間:2016年6月11日19時33分46秒,執(zhí)行方法"add"?? 執(zhí)行結(jié)果:添加文檔《轉(zhuǎn)角遇見幸福》成功...?? 北京時間:2016年6月11日19時33分46秒,執(zhí)行方法"add"?? 執(zhí)行結(jié)果:添加文檔《轉(zhuǎn)角遇見幸福》失敗,文檔已存在!?? 北京時間:2016年6月11日19時33分46秒,執(zhí)行方法"logout"?? 執(zhí)行結(jié)果:用戶[燕凌嬌]退出登陸成功...?? **********************************?? 從以上程序的最終運行結(jié)果可以看出:通過使用JDK自帶的動態(tài)代理,我們同時實現(xiàn)了對ImpUserDao和ImpDocumentDao兩個真實主題類的統(tǒng)一代理和集中控制。至于該動態(tài)代理類是如何被創(chuàng)建的?將在下一篇文章詳細討論,接下來我們先看看如何使用CGLIB實現(xiàn)動態(tài)代理。
三、使用CGLIB實現(xiàn)動態(tài)代理
生成動態(tài)代理類的方法很多,如上例中JDK自帶的動態(tài)代理、CGLIB、Javassist 或者 ASM 庫。JDK 的動態(tài)代理使用簡單,它內(nèi)置在 JDK 中,因此不需要引入第三方 Jar 包,但相對功能比較弱。CGLIB 和 Javassist 都是高級的字節(jié)碼生成庫,總體性能比 JDK 自帶的動態(tài)代理好,而且功能十分強大。ASM 是低級的字節(jié)碼生成工具,使用 ASM 已經(jīng)近乎于在使用 Java bytecode 編程,對開發(fā)人員要求最高,當然,也是性能最好的一種動態(tài)代理生成工具。但 ASM 的使用很繁瑣,而且性能也沒有數(shù)量級的提升,與 CGLIB 等高級字節(jié)碼生成工具相比,ASM 程序的維護性較差,如果不是在對性能有苛刻要求的場合,還是推薦 CGLIB 或者 Javassist。
接下來我們繼續(xù)用上面的例子來體驗一下如何使用CGLIB實現(xiàn)動態(tài)代理。
首先,使用CGLIB來實現(xiàn)動態(tài)代理需引入“asm.jar”(CGLIB的底層是使用ASM實現(xiàn)的)和“cglib.jar”兩個第三方jar包,引入兩個jar包時需注意其版本,若版本有沖突會出現(xiàn)以下異常:Exception in thread "main" java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V
接下來開始寫代碼,延用上例中的:User類、Document類、DataBase類、兩個抽象主題接口UserDao和DocumentDao、兩個真實主題角色類ImpUserDao和ImpDocumentDao,這幾個類無需做任何修改,此處不再重復貼出。
去掉上例中的 DataBaseLogHandler 類,新增一個 CglibProxy 類,該類需實現(xiàn)CGLIB的 MethodInterceptor(方法攔截) 接口。
[java]?view plaincopy
import?java.lang.reflect.Method;?? import?java.util.Calendar;?? import?java.util.GregorianCalendar;?? import?net.sf.cglib.proxy.Enhancer;?? import?net.sf.cglib.proxy.MethodInterceptor;?? import?net.sf.cglib.proxy.MethodProxy;?? ?? public?class?CglibProxy?implements?MethodInterceptor?{?? ?private?Calendar?calendar;?? ?? ? ? ? ? ? ?? ?public?Object?getProxyInstance(Class<?>?clazz)?{?? ??Enhancer?enhancer?=?new?Enhancer();?? ???? ??enhancer.setSuperclass(clazz);?? ???? ??enhancer.setCallback(this);?? ???? ??return?enhancer.create();?? ?}?? ?@Override?? ??? ?public?Object?intercept(Object?obj,?Method?method,?Object[]?args,?? ???MethodProxy?proxy)?throws?Throwable?{?? ??before(method);?? ???? ??Object?result?=?proxy.invokeSuper(obj,?args);?? ??after(result);?? ??if?(method.getName().equalsIgnoreCase("logout"))?{?? ???System.out.println("**********************************");?? ???System.out.println("");?? ??}?? ??return?result;?? ?}?? ?public?void?before(Method?method)?{?? ??calendar?=?new?GregorianCalendar();?? ??int?year?=?calendar.get(Calendar.YEAR);?? ??int?month?=?calendar.get(Calendar.MONTH);?? ??int?date?=?calendar.get(Calendar.DATE);?? ??int?hour?=?calendar.get(Calendar.HOUR_OF_DAY);?? ??int?minute?=?calendar.get(Calendar.MINUTE);?? ??int?second?=?calendar.get(Calendar.SECOND);?? ??String?time?=?hour?+?"時"?+?minute?+?"分"?+?second?+?"秒";?? ??System.out.println("北京時間:"?+?year?+?"年"?+?month?+?"月"?+?date?+?"日"?? ????+?time?+?",執(zhí)行方法\""?+?method.getName()?+?"\"");?? ?}?? ?public?void?after(Object?object)?{?? ??System.out.println("執(zhí)行結(jié)果:"?+?object);?? ?}?? }?? 對客戶端進行相應修改,如下。
[java]?view plaincopy
public?class?Client{?? ?public?static?void?main(String[]?args)?{?? ???? ??CglibProxy?cglib?=?new?CglibProxy();?? ???? ??UserDao?userProxy?=?(UserDao)?cglib.getProxyInstance(ImpUserDao.class);?? ???? ??DocumentDao?documentProxy?=?(DocumentDao)?cglib?? ????.getProxyInstance(ImpDocumentDao.class);?? ???? ??userProxy.login(20160718L);?? ??documentProxy.add(new?Document(30160711L,?"轉(zhuǎn)角遇見幸福"));?? ??userProxy.logout();?? ???? ??userProxy.login(20160708L);?? ??documentProxy.add(new?Document(30160711L,?"轉(zhuǎn)角遇見幸福"));?? ??documentProxy.add(new?Document(30160711L,?"轉(zhuǎn)角遇見幸福"));?? ??userProxy.logout();?? ?}?? }?? 運行程序結(jié)果打印如下,與之前使用JDK自帶動態(tài)代理程序運行結(jié)果完全相同:
[html]?view plaincopy
北京時間:2016年6月12日20時22分35秒,執(zhí)行方法"login"?? 執(zhí)行結(jié)果:登陸失敗,ID為"20160718"的用戶不存在!?? 北京時間:2016年6月12日20時22分35秒,執(zhí)行方法"add"?? 執(zhí)行結(jié)果:保存失敗,未獲取到登陸信息!?? 北京時間:2016年6月12日20時22分35秒,執(zhí)行方法"logout"?? 執(zhí)行結(jié)果:退出登陸失敗,當前無登陸用戶!?? **********************************?? 北京時間:2016年6月12日20時22分35秒,執(zhí)行方法"login"?? 執(zhí)行結(jié)果:用戶[燕凌嬌]登陸成功...?? 北京時間:2016年6月12日20時22分35秒,執(zhí)行方法"add"?? 執(zhí)行結(jié)果:添加文檔《轉(zhuǎn)角遇見幸福》成功...?? 北京時間:2016年6月12日20時22分35秒,執(zhí)行方法"add"?? 執(zhí)行結(jié)果:添加文檔《轉(zhuǎn)角遇見幸福》失敗,文檔已存在!?? 北京時間:2016年6月12日20時22分35秒,執(zhí)行方法"logout"?? 執(zhí)行結(jié)果:用戶[燕凌嬌]退出登陸成功...?? **********************************?? PS:CGLib創(chuàng)建的動態(tài)代理對象性能比JDK創(chuàng)建的動態(tài)代理對象的性能高不少,但是CGLib在創(chuàng)建代理對象時所花費的時間卻比JDK多得多,所以對于單例的對象,因為無需頻繁創(chuàng)建對象,用CGLib合適,反之,使用JDK方式要更為合適一些。同時,由于CGLib采用動態(tài)創(chuàng)建子類的方法來對被代理的父類的功能進行增強和代理,所以,無法對被聲明為final的類或方法進行代理。
四、動態(tài)代理模式的特點
動態(tài)代理類使用字節(jié)碼動態(tài)生成加載技術(shù),在運行時生成并加載代理類。與靜態(tài)代理相比,動態(tài)代理具有以下優(yōu)點:
-無需單獨為每一個接口添加一個代理類,使用動態(tài)代理可以一次性為多個接口實現(xiàn)代理。
-無需逐個為接口中的所有方法添加實現(xiàn),使用動態(tài)代理可以一次性為多個接口中的所有方法實現(xiàn)代理,在接口方法數(shù)量比較多的時候,可以避免出現(xiàn)大量的重復代碼。
動態(tài)代理的缺點:
目前,JDK中提供的動態(tài)代理只能對接口實現(xiàn)代理,無法代理未實現(xiàn)接口的類。如果需要動態(tài)代理未實現(xiàn)接口的類,必須借助第三方工具,如:CGLib(Code Generation Library)等。
總結(jié)
以上是生活随笔為你收集整理的JAVA设计模式-11-代理模式(动态)(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。