日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

JAVA设计模式-11-代理模式(动态)(一)

發布時間:2023/12/16 asp.net 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA设计模式-11-代理模式(动态)(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
java的動態代理機制詳解 代理模式原理及實例講解 代理模式詳解包含原理詳解 Java動態代理的實現 JAVA學習篇--靜態代理VS動態代理 深入理解Java Proxy機制
一、什么是動態代理
在靜態代理(Static Proxy)模式中,代理類都是真實存在的,由程序員提前創建好的java類,是靜態的,每一個代理類在編譯之后都會生成一個.class字節碼文件,靜態代理類所實現的接口和所代理的方法早在編譯期都已被固定了。
動態代理(Dynamic Proxy)則不同:動態代理使用字節碼動態生成和加載技術,在系統運行時動態地生成和加載代理類。
與靜態代理相比,動態代理有以下優點:首先,無需再為每一個真實主題寫一個形式上完全一樣的代理類,假如抽象主題接口中的方法很多的話,為每一個接口方法寫一個代理方法也很麻煩,同樣地,如果后期抽象主題接口發生變動,則真實主題和代理類都要修改,不利于系統維護;其次,動態代理可以讓系統根據實際需要來動態創建代理類,同一個代理類能夠代理多個不同的真實主題類,并且可以代理多個不同的方法。
二、Java對動態代理的支持

從JDK 1.3版本開始,Java語言提供了對動態代理的支持,在Java中實現動態代理機制,需要用到 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?是代理實例的調用處理程序實現的接口。??
  • 每個代理實例都具有一個與之關聯的調用處理程序。對代理實例調用方法時,將對方法調用進行編碼并將其指派到它的調用處理程??
  • 序的?invoke()?方法。??
  • invoke() 方法形式如下:

    [java]?view plaincopy
  • Object?invoke(Object?proxy,??
  • Method?method,??
  • Object[]?args)??
  • throws?Throwable??
  • InvocationHandler 接口只包含invoke()這唯一一個方法,該方法用于處理對代理類實例的方法調用并返回相應的結果,當一個代理實例中的業務方法被調用時將自動調用該方法。invoke()方法包含三個參數,其中第一個參數proxy表示代理類的實例,第二個參數method表示需要代理的方法,第三個參數args表示代理方法的參數數組。

    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?提供用于創建動態代理類和實例的靜態方法,它還是由這些方法創建的所有動態代理類的超類。??
  • Proxy提供給我們的靜態方法有以下四個:
    [html]?view plaincopy
  • //返回指定代理實例的調用處理程序。??
  • static?InvocationHandler?getInvocationHandler(Object?proxy)???
  • //返回代理類的?java.lang.Class?對象,并向其提供類加載器和接口數組。??
  • static?Class<?><span?style="white-space:pre">???</span>getProxyClass(ClassLoader?loader,?Class<?>[]?interfaces)???
  • //當且僅當指定的類通過?getProxyClass?方法或?newProxyInstance?方法動態生成為代理類時,返回?true。??
  • static?boolean<span?style="white-space:pre">??</span>isProxyClass(Class<?>?cl)???
  • ??
  • //返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。??
  • //方法中的?ClassLoader?loader?參數用來指定動態代理類的類加載器,Class<?>[]?interfaces用來指定動態代理類要實現的接口。??
  • //InvocationHandler?h?用來指定與即將生成的動態代理對象相關聯的調用處理程序??
  • static?Object<span?style="white-space:pre">???</span>newProxyInstance(ClassLoader?loader,?Class<?>[]?interfaces,?InvocationHandler?h)???
  • 下面我們以為數據庫增加日志記錄功能(為簡單起見,我們僅記錄下所有操作的執行時間及操作執行的結果)為例來看一看如何使用這兩個類實現動態代理:
    為了使演示更清晰,在此先定義兩個簡單類,一個User類和一個Document類分別表示數據庫中的用戶記錄和文檔記錄,其代碼如下。

    [java]?view plaincopy
  • public?class?User?{??
  • ?//?用戶在數據庫中的ID??
  • ?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?{??
  • ?//?文檔在數據庫中的ID??
  • ?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類用來扮演數據庫的功能,在此為簡單起見,將數據庫中的用戶記錄和文檔記錄分別存儲在一個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內核設計思想"));??
  • ??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();??
  • ?}??
  • }??
  • 數據庫布置完成了,接下來開始寫動態代理相關代碼了,為了與靜態代理進行比較,在此我們來創建兩個接口(抽象主題角色)。

    [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類,為了使示例結果清晰,此處將接口的執行結果直接以字符串形式返回。

    [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)?{??
  • ????//?若數據庫中已經存在該ID的文檔,則新增文檔失敗...??
  • ????return?"添加文檔《"?+?document.getTitle()?+?"》失敗,文檔已存在!";??
  • ???}?else?{??
  • ????//?若該ID的文檔在數據庫不存在,則新增文檔成功...??
  • ????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()?+?"》成功...";??
  • ???}??
  • ??}??
  • ?}??
  • }??
  • 最后,我們就要定義動態代理類了,前面說過,每一個動態代理類都必須要實現 InvocationHandler 這個接口,因此我們這個動態代理類也不例外。

    [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;??
  • ?}??
  • ?//invoke()方法用于處理對代理類實例的方法調用并返回相應的結果??
  • ?@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?+?",執行方法\""?+?method.getName()?+?"\"");??
  • ?}??
  • ?public?void?after(Object?object)?{??
  • ??System.out.println("執行結果:"?+?object);??
  • ?}??
  • }??
  • 至此,動態代理所需要的類就算創建完成了,接下來創建一個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);??
  • ??//?先輸入一個不存在的用戶Id登陸試試...??
  • ??userProxy.login(20160718L);??
  • ??documentProxy.add(new?Document(30160711L,?"轉角遇見幸福"));??
  • ??userProxy.logout();??
  • ??//?再用一個真實用戶Id登陸試試...??
  • ??userProxy.login(20160708L);??
  • ??documentProxy.add(new?Document(30160711L,?"轉角遇見幸福"));??
  • ??documentProxy.add(new?Document(30160711L,?"轉角遇見幸福"));??
  • ??userProxy.logout();??
  • ?}??
  • }??
  • 運行程序打印結果如下:

    [html]?view plaincopy
  • 北京時間:2016年6月11日19時33分46秒,執行方法"login"??
  • 執行結果:登陸失敗,ID為"20160718"的用戶不存在!??
  • 北京時間:2016年6月11日19時33分46秒,執行方法"add"??
  • 執行結果:保存失敗,未獲取到登陸信息!??
  • 北京時間:2016年6月11日19時33分46秒,執行方法"logout"??
  • 執行結果:退出登陸失敗,當前無登陸用戶!??
  • **********************************??
  • ??
  • 北京時間:2016年6月11日19時33分46秒,執行方法"login"??
  • 執行結果:用戶[燕凌嬌]登陸成功...??
  • 北京時間:2016年6月11日19時33分46秒,執行方法"add"??
  • 執行結果:添加文檔《轉角遇見幸福》成功...??
  • 北京時間:2016年6月11日19時33分46秒,執行方法"add"??
  • 執行結果:添加文檔《轉角遇見幸福》失敗,文檔已存在!??
  • 北京時間:2016年6月11日19時33分46秒,執行方法"logout"??
  • 執行結果:用戶[燕凌嬌]退出登陸成功...??
  • **********************************??
  • 從以上程序的最終運行結果可以看出:通過使用JDK自帶的動態代理,我們同時實現了對ImpUserDao和ImpDocumentDao兩個真實主題類的統一代理和集中控制。至于該動態代理類是如何被創建的?將在下一篇文章詳細討論,接下來我們先看看如何使用CGLIB實現動態代理。

    三、使用CGLIB實現動態代理

    生成動態代理類的方法很多,如上例中JDK自帶的動態代理、CGLIB、Javassist 或者 ASM 庫。JDK 的動態代理使用簡單,它內置在 JDK 中,因此不需要引入第三方 Jar 包,但相對功能比較弱。CGLIB 和 Javassist 都是高級的字節碼生成庫,總體性能比 JDK 自帶的動態代理好,而且功能十分強大。ASM 是低級的字節碼生成工具,使用 ASM 已經近乎于在使用 Java bytecode 編程,對開發人員要求最高,當然,也是性能最好的一種動態代理生成工具。但 ASM 的使用很繁瑣,而且性能也沒有數量級的提升,與 CGLIB 等高級字節碼生成工具相比,ASM 程序的維護性較差,如果不是在對性能有苛刻要求的場合,還是推薦 CGLIB 或者 Javassist。
    接下來我們繼續用上面的例子來體驗一下如何使用CGLIB實現動態代理。
    首先,使用CGLIB來實現動態代理需引入“asm.jar”(CGLIB的底層是使用ASM實現的)和“cglib.jar”兩個第三方jar包,引入兩個jar包時需注意其版本,若版本有沖突會出現以下異常:Exception in thread "main" java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V
    接下來開始寫代碼,延用上例中的:User類、Document類、DataBase類、兩個抽象主題接口UserDao和DocumentDao、兩個真實主題角色類ImpUserDao和ImpDocumentDao,這幾個類無需做任何修改,此處不再重復貼出。
    去掉上例中的 DataBaseLogHandler 類,新增一個 CglibProxy 類,該類需實現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;??
  • ?/**?
  • ??*?創建動態代理類對象?
  • ??*?
  • ??*?@param?clazz??需要創建子類代理的父類的類型?
  • ??*????????????
  • ??*?@return?
  • ??*/??
  • ?public?Object?getProxyInstance(Class<?>?clazz)?{??
  • ??Enhancer?enhancer?=?new?Enhancer();??
  • ??//?設置要創建的動態代理類的父類??
  • ??enhancer.setSuperclass(clazz);??
  • ??//?設置回調的對象,此句會導致調用動態代理類對象的方法會被指派到CglibProxy對象的intercept()方法??
  • ??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?+?",執行方法\""?+?method.getName()?+?"\"");??
  • ?}??
  • ?public?void?after(Object?object)?{??
  • ??System.out.println("執行結果:"?+?object);??
  • ?}??
  • }??
  • 對客戶端進行相應修改,如下。

    [java]?view plaincopy
  • public?class?Client{??
  • ?public?static?void?main(String[]?args)?{??
  • ??//?創建一個CglibProxy代理類對象,用來創建子類代理實例??
  • ??CglibProxy?cglib?=?new?CglibProxy();??
  • ??//?為ImpUserDao類添加一個動態代理類對象,即子類代理對象??
  • ??UserDao?userProxy?=?(UserDao)?cglib.getProxyInstance(ImpUserDao.class);??
  • ??//?為ImpDocumentDao類添加一個動態代理類對象,即子類代理對象??
  • ??DocumentDao?documentProxy?=?(DocumentDao)?cglib??
  • ????.getProxyInstance(ImpDocumentDao.class);??
  • ??//?先輸入一個不存在的用戶Id登陸試試...??
  • ??userProxy.login(20160718L);??
  • ??documentProxy.add(new?Document(30160711L,?"轉角遇見幸福"));??
  • ??userProxy.logout();??
  • ??//?再用一個真實用戶Id登陸試試...??
  • ??userProxy.login(20160708L);??
  • ??documentProxy.add(new?Document(30160711L,?"轉角遇見幸福"));??
  • ??documentProxy.add(new?Document(30160711L,?"轉角遇見幸福"));??
  • ??userProxy.logout();??
  • ?}??
  • }??
  • 運行程序結果打印如下,與之前使用JDK自帶動態代理程序運行結果完全相同:

    [html]?view plaincopy
  • 北京時間:2016年6月12日20時22分35秒,執行方法"login"??
  • 執行結果:登陸失敗,ID為"20160718"的用戶不存在!??
  • 北京時間:2016年6月12日20時22分35秒,執行方法"add"??
  • 執行結果:保存失敗,未獲取到登陸信息!??
  • 北京時間:2016年6月12日20時22分35秒,執行方法"logout"??
  • 執行結果:退出登陸失敗,當前無登陸用戶!??
  • **********************************??
  • 北京時間:2016年6月12日20時22分35秒,執行方法"login"??
  • 執行結果:用戶[燕凌嬌]登陸成功...??
  • 北京時間:2016年6月12日20時22分35秒,執行方法"add"??
  • 執行結果:添加文檔《轉角遇見幸福》成功...??
  • 北京時間:2016年6月12日20時22分35秒,執行方法"add"??
  • 執行結果:添加文檔《轉角遇見幸福》失敗,文檔已存在!??
  • 北京時間:2016年6月12日20時22分35秒,執行方法"logout"??
  • 執行結果:用戶[燕凌嬌]退出登陸成功...??
  • **********************************??
  • PS:CGLib創建的動態代理對象性能比JDK創建的動態代理對象的性能高不少,但是CGLib在創建代理對象時所花費的時間卻比JDK多得多,所以對于單例的對象,因為無需頻繁創建對象,用CGLib合適,反之,使用JDK方式要更為合適一些。同時,由于CGLib采用動態創建子類的方法來對被代理的父類的功能進行增強和代理,所以,無法對被聲明為final的類或方法進行代理。

    四、動態代理模式的特點

    動態代理類使用字節碼動態生成加載技術,在運行時生成并加載代理類。與靜態代理相比,動態代理具有以下優點:

    -無需單獨為每一個接口添加一個代理類,使用動態代理可以一次性為多個接口實現代理。
    -無需逐個為接口中的所有方法添加實現,使用動態代理可以一次性為多個接口中的所有方法實現代理,在接口方法數量比較多的時候,可以避免出現大量的重復代碼。

    動態代理的缺點:
    目前,JDK中提供的動態代理只能對接口實現代理,無法代理未實現接口的類。如果需要動態代理未實現接口的類,必須借助第三方工具,如:CGLib(Code Generation Library)等。

    總結

    以上是生活随笔為你收集整理的JAVA设计模式-11-代理模式(动态)(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。