java動態代理的實現

動態代理作為代理模式的一種擴展形式,廣泛應用于框架(尤其是基于AOP的框架)的設計與開發,本文將通過實例來講解Java動態代理的實現過程。

???????友情提示:本文略有難度,讀者需具備代理模式相關基礎知識微笑

?

????????通常情況下,代理模式中的每一個代理類在編譯之后都會生成一個class文件,代理類所實現的接口和所代理的方法都被固定,這種代理被稱之為靜態代理(Static Proxy)。那么有沒有一種機制能夠讓系統在運行時動態創建代理類?答案就是本文將要介紹的動態代理(Dynamic Proxy)。動態代理是一種較為高級的代理模式,它在事務管理、AOP(Aspect-OrientedProgramming,面向方面編程)等領域都發揮了重要的作用。

?

????? 在傳統的代理模式中,客戶端通過Proxy類調用RealSubject類的request()方法,同時還可以在代理類中封裝其他方法(如preRequest()和postRequest()等)。如果按照這種方法使用代理模式,那么代理類和真實主題類都應該是事先已經存在的,代理類的接口和所代理方法都已明確指定,如果需要為不同的真實主題類提供代理類或者代理一個真實主題類中的不同方法,都需要增加新的代理類,這將導致系統中的類個數急劇增加,因此需要想辦法減少系統中類的個數。動態代理可以讓系統能夠根據實際需要來動態創建代理類,讓同一個代理類能夠代理多個不同的真實主題類而且可以代理不同的方法。

?

?????? 從JDK 1.3開始,Java語言提供了對動態代理的支持,Java語言實現動態代理時需要用到位于java.lang.reflect包中的一些類,現簡要說明如下:

?

????? (1) Proxy類

??????Proxy類提供了用于創建動態代理類和實例對象的方法,它是所創建的動態代理類的父類,它最常用的方法如下:

  • public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces):該方法用于返回一個Class類型的代理類,在參數中需要提供類加載器并需要指定代理的接口數組(與真實主題類的接口列表一致)。
  • public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces, InvocationHandler h):該方法用于返回一個動態創建的代理類的實例,方法中第一個參數loader表示代理類的類加載器,第二個參數interfaces表示代理類所實現的接口列表(與真實主題類的接口列表一致),第三個參數h表示所指派的調用處理程序類。

??????(2) InvocationHandler接口

??????InvocationHandler接口是代理處理程序類的實現接口,該接口作為代理實例的調用處理者的公共父類,每一個代理類的實例都可以提供一個相關的具體調用處理者(InvocationHandler接口的子類)。在該接口中聲明了如下方法:

  • public Object invoke(Objectproxy, Method method, Object[] args):該方法用于處理對代理類實例的方法調用并返回相應的結果,當一個代理實例中的業務方法被調用時將自動調用該方法。invoke()方法包含三個參數,其中第一個參數proxy表示代理類的實例,第二個參數method表示需要代理的方法,第三個參數args表示代理方法的參數數組。

?????? ?動態代理類需要在運行時指定所代理真實主題類的接口,客戶端在調用動態代理對象的方法時,調用請求會將請求自動轉發給InvocationHandler對象的invoke()方法,由invoke()方法來實現對請求的統一處理。

?

??????下面通過一個簡單實例來學習如何使用動態代理模式:

?????? Sunny軟件公司欲為公司OA系統數據訪問層DAO增加方法調用日志,記錄每一個方法被調用的時間和調用結果,現使用動態代理進行設計和實現。

?

????? 本實例完整代碼如下所示:

[java]?view plain?copy
  1. import?java.lang.reflect.Proxy;??
  2. import?java.lang.reflect.InvocationHandler;??
  3. import?java.lang.reflect.InvocationTargetException;??
  4. import?java.lang.reflect.Method;??
  5. import?java.util.Calendar;??
  6. import?java.util.GregorianCalendar;??
  7. ??
  8. //抽象UserDAO:抽象主題角色??
  9. interface?AbstractUserDAO?{??
  10. ????public?Boolean?findUserById(String?userId);??
  11. }??
  12. ??
  13. //抽象DocumentDAO:抽象主題角色??
  14. interface?AbstractDocumentDAO?{??
  15. ????public?Boolean?deleteDocumentById(String?documentId);??
  16. }??
  17. ??
  18. //具體UserDAO類:真實主題角色??
  19. class?UserDAO?implements?AbstractUserDAO?{??
  20. ????public?Boolean?findUserById(String?userId)?{??
  21. ????????if?(userId.equalsIgnoreCase("張無忌"))?{??
  22. ????????????System.out.println("查詢ID為"?+?userId?+?"的用戶信息成功!");??
  23. ????????????return?true;??
  24. ????????}??
  25. ????????else?{??
  26. ????????????System.out.println("查詢ID為"?+?userId?+?"的用戶信息失敗!");??
  27. ????????????return?false;??
  28. ????????}??
  29. ????}??
  30. }??
  31. ??
  32. //具體DocumentDAO類:真實主題角色??
  33. class?DocumentDAO?implements?AbstractDocumentDAO?{??
  34. ????public?Boolean?deleteDocumentById(String?documentId)?{??
  35. ????????if?(documentId.equalsIgnoreCase("D001"))?{??
  36. ????????????System.out.println("刪除ID為"?+?documentId?+?"的文檔信息成功!");??
  37. ????????????return?true;??
  38. ????????}??
  39. ????????else?{??
  40. ????????????System.out.println("刪除ID為"?+?documentId?+?"的文檔信息失敗!");??
  41. ????????????return?false;??
  42. ????????}??
  43. ????}??
  44. }??
  45. ??
  46. //自定義請求處理程序類??
  47. class?DAOLogHandler?implements?InvocationHandler?{??
  48. ????private?Calendar?calendar;??
  49. ????private?Object?object;??
  50. ??????
  51. ????public?DAOLogHandler()?{??????
  52. ????}??
  53. ??????
  54. ????//自定義有參構造函數,用于注入一個需要提供代理的真實主題對象??
  55. ????public?DAOLogHandler(Object?object)?{??
  56. ????????this.object?=?object;??
  57. ????}??
  58. ??????
  59. ????//實現invoke()方法,調用在真實主題類中定義的方法??
  60. ????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{??
  61. ????????beforeInvoke();??
  62. ????????Object?result?=?method.invoke(object,?args);?//轉發調用??
  63. ????????afterInvoke();??
  64. ????????return?null;??
  65. ????}??
  66. ??
  67. ????//記錄方法調用時間??
  68. ????public?void?beforeInvoke(){??
  69. ????????calendar?=?new?GregorianCalendar();??
  70. ????????int?hour?=?calendar.get(Calendar.HOUR_OF_DAY);??
  71. ????????int?minute?=?calendar.get(Calendar.MINUTE);??
  72. ????????int?second?=?calendar.get(Calendar.SECOND);??
  73. ????????String?time?=?hour?+?":"?+?minute?+?":"?+?second;??
  74. ????????System.out.println("調用時間:"?+?time);??
  75. ????}??
  76. ??
  77. ????public?void?afterInvoke(){??
  78. ????????System.out.println("方法調用結束!"?);??
  79. ????}??
  80. }??

????? 編寫如下客戶端測試代碼:

[java]?view plain?copy
  1. class?Client?{??
  2. ????public?static?void?main(String?args[])?{??
  3. ????????InvocationHandler?handler?=?null;??
  4. ??????????
  5. ????????AbstractUserDAO?userDAO?=?new?UserDAO();??
  6. ????????handler?=?new?DAOLogHandler(userDAO);??
  7. ????????AbstractUserDAO?proxy?=?null;??
  8. ????????//動態創建代理對象,用于代理一個AbstractUserDAO類型的真實主題對象??
  9. ????????proxy?=?(AbstractUserDAO)Proxy.newProxyInstance(AbstractUserDAO.?class.getClassLoader(),?new?Class[]{AbstractUserDAO.class},?handler);??
  10. ????????proxy.findUserById("張無忌");?//調用代理對象的業務方法??
  11. ??????
  12. ????????System.out.println("------------------------------");??
  13. ??????
  14. ????????AbstractDocumentDAO?docDAO?=?new?DocumentDAO();??
  15. ????????handler?=?new?DAOLogHandler(docDAO);??
  16. ????????AbstractDocumentDAO?proxy_new?=?null;??
  17. //動態創建代理對象,用于代理一個AbstractDocumentDAO類型的真實主題對象??
  18. ????????proxy_new?=?(AbstractDocumentDAO)Proxy.newProxyInstance(Abstract?DocumentDAO.class.getClassLoader(),?new?Class[]{AbstractDocumentDAO.class},?handler);??
  19. ????????proxy_new.deleteDocumentById("D002");?//調用代理對象的業務方法??
  20. ????}???
  21. }??

????? 編譯并運行程序,輸出結果如下:

調用時間:13:47:14

查詢ID為張無忌的用戶信息成功!

方法調用結束!

------------------------------

調用時間:13:47:14

刪除ID為D002的文檔信息失敗!

方法調用結束!

???????通過使用動態代理,我們可以實現對多個真實主題類的統一代理和集中控制。

???????注:JDK中提供的動態代理只能代理一個或多個接口,如果需要動態代理具體類或抽象類,可以使用CGLib(Code Generation Library)等工具,CGLib是一個功能較為強大、性能和質量也較好的代碼生成包,在許多AOP框架中都得以廣泛應用,大家可以自行查閱相關資料來學習CGLib。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458987.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458987.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458987.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常見的網絡類型

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 我們經常聽到Internet網、星形網等名詞&#xff0c;它們表示什么&#xff1f;是怎樣分…

oracle放在內存里,oracle如中何把小表釘住在內存中

buffer_pool_defualtbuffer_pool_keepbuffer_pool_recycle如果要把表釘死在內存中&#xff0c;也就是把表釘在keep區。相關的命令為&#xff1a;alter table ..... storage(buffer_pool keep);這句命令把表示表如果緩存的話是緩存在keep區。可以通過語句&#xff1a;select tab…

C++基礎之this指針的詳解

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 關于C中的this指針&#xff0c;建議大家看看這篇文章&#xff0c;《C中的this指針》&a…

xcode 開發ios兼容性問題的上下黑邊 和 coco2d-x 游戲分辨率適配 ResolutionPolicy::FIXED_WIDTH 都會引起上下黑邊問題!!!...

1&#xff1a;Xcode6在iPhone5iOS7模擬器上編譯&#xff0c;上下有黑邊問題 問題描述&#xff1a; Xcode6環境下&#xff0c;對iPhone5或iPhone5s模擬器&#xff0c;在iOS7或iOS7.1下運行&#xff0c;屏幕上下有黑邊。在iOS8下沒問題。 問題分析&#xff1a; 這種熟悉的場景又出…

如何用參數化SQL語句污染你的計劃緩存

你的SQL語句的參數化總是個好想法。使用參數化SQL語句你不會污染你的計劃緩存——錯&#xff01;&#xff01;&#xff01;在這篇文章里我想向你展示下用參數化SQL語句就可以污染你的計劃緩存&#xff0c;這是非常簡單的&#xff01; ADO.NET-AddWithValue ADO.NET是實現像SQL …

oracle values函數,Oracle文本函數簡介

Oracle文本函數使我們常用的函數&#xff0c;下面就為您介紹幾種Oracle文本函數的用法&#xff0c;供您參考學習&#xff0c;希望可以讓您對Oracle文本函數有更深的認識。(1)UPPER、LOWER和INITCAP這三個函數更改提供給它們的文體的大小寫。select upper(product_name) from pr…

c++ int *p = new int()

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** int *anew int(120); 申請一個整型變量空間&#xff0c;賦初值為120&#xff0c;并…

Ios: 如何保護iOS束文件屬性列表,圖像,SQLite,媒體文件

Ios: 如何保護iOS束文件屬性列表&#xff0c;圖像&#xff0c;SQLite&#xff0c;媒體文件我創建了Hello World示例項目&#xff0c;然後添加data.plist文件到資源文件夾。現在人們可以很容易得到束文件解壓縮。國際音標。有任何的方法來保護data.plist文件保存在iPhone應用程序…

w3wp oracle,w3wp.exe占用CPU超過50%的處理

w3wp.exe占用CPU超過50%的處理1.查看CPU占用高的進程&#xff1a;任務管理器C:\Documents andSettings\Administrator>iisappW3WP.exe PID: 18008 AppPoolId: STATW3WP.exe PID: 8328 AppPoolId: STATW3WP.exe PID: 17868 AppPoolId: JYCV16W3WP.exe PID: 16652 AppPoolId: …

論兩種學習模式

引言 A&#xff1a;你是如何學習的&#xff0c;通過視頻、書籍和實踐結合&#xff1f;B&#xff1a;不是&#xff0c;一般情況是以一個問題為點去畫線和面。 兩種學習模式 按部就班方式獲取知識(通過書、視頻)缺點 信息接收者缺乏深度思考和探索信息發布者的知識體系不一定適合…

啟動mq命令 linux,RocketMQ:Linux下啟動server和broker的命令

目錄QUESTION:RocketMQ&#xff1a;Linux下啟動server和broker的命令?ANSWER:一、啟動mqnamesrv1.1當前執行1.2后臺運行二、啟動mqbroker2.1當前執行2.2后臺運行QUESTION:RocketMQ&#xff1a;Linux下啟動server和broker的命令?ANSWER:一、啟動mqnamesrv1.1當前執行進入rocke…

C++中int *p[4]和 int (*q)[4]的區別

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** C中int *p[4]和 int (*q)[4]的區別 前者是指針數組&#xff0c;后者是指向數組的指針…

Spring筆記③--spring的命名空間

p:命名空間: xmlns:p"http://www.springframework.org/schema/p" 作用:簡化在xml配置bean的屬性 在<bean>中使用p:屬性名來配置 AOP:命名空間: xmlns:aop"http://www.springframework.org/schema/aop" xsi:schemaLocation: http://www.springframewo…

linux不用命令開啟ssh,不用密碼也能ssh登陸Linux?

Linux的一個后門引發對PAM的探究1.1 起因今天在搜索關于Linux下的后門姿勢時&#xff0c;發現一條命令如下&#xff1a;ln -sf /usr/sbin/sshd /tmp/su; /tmp/su -oPort5555;經典后門。直接對sshd建立軟連接&#xff0c;之后用任意密碼登錄即可。ssh rootx.x.x.x -p 5555這個是…

ScrollView常用(暫時用上了的)代理方法

2019獨角獸企業重金招聘Python工程師標準>>> ScrollView常用代理方法: #pragma mark - 滾動結束調用 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {// 計算 滑動到了第幾頁double page scrollView.contentOffset.x / scrollView.width;self.p…

筆試題目匯總

C常考筆試題:不用if,while,do-while,for,打印出所有大于0小于k的整數.函數原型void printLess(int k); 解法一:遞歸方式(剛想出來) [cpp] view plaincopy #include <iostream> using namespace std; void printLess(int k) { switch(--k) { case 0:…

Android ListView性能優化實例講解

前言&#xff1a; 對于ListView&#xff0c;大家絕對都不會陌生&#xff0c;只要是做過Android開發的人&#xff0c;哪有不用ListView的呢&#xff1f; 只要是用過ListView的人&#xff0c;哪有不關心對它性能優化的呢&#xff1f; 關于如何對ListView進行性能優化&#xff0c;…

Bzoj 3289: Mato的文件管理 莫隊,樹狀數組,逆序對,離散化,分塊

3289: Mato的文件管理 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1539 Solved: 665[Submit][Status][Discuss]Description Mato同學從各路神犇以各種方式&#xff08;你們懂的&#xff09;收集了許多資料&#xff0c;這些資料一共有n份&#xff0c;每份有一個大小和一…

linux頭文件 庫,Linux操作系統的頭文件和庫文件搜索路徑

一、 頭文件1 “”中的頭文件&#xff0c;在源文件當前目錄查找2 -I 中指定目錄 -I可以在CFLAG中指定3 gcc的環境變量 C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, OBJC_INCLUDE_PATH4 編譯器預設路徑、內定目錄&#xff1a;/usr/include/usr/local/include/usr/lib/gcc-lib/i386-lin…

vs2010創建和使用動態鏈接庫(dll)

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 本文將創建一個簡單的動態鏈接庫&#xff0c;并編寫一個應用臺控制程序使用該動態鏈接…