摘要:這種語法,在中被稱為動態代理。在動態代理機制中,這個角色只能是接口。動態代理就是實現的技術之一。
所謂動態代理,指的是語言提供的一種語法,能夠將對對象中不同方法的調用重定向到一個統一的處理函數中來。
python重寫__getattr__函數能夠做到這一點,就連世界上最好的語言也提供稱為魔術方法的__call。
這種語法除了能更好的實現動態代理外,還是RPC框架實現原理的一部分。
動態代理提供一種抽象,能夠將對象中不同方法的調用重定向到一個統一的處理函數,做自定義的邏輯處理。
但是對于調用者,對此毫無察覺,就好像調用的方法是用傳統方式實現的一般。
這種語法,在java中被稱為動態代理。之所以叫做動態代理,是因為它能避免傳統代理模式實現中人工一個一個的將java函數轉發過去,
而是能夠讓代碼自動做到這一點,這樣代理類的代碼是和業務無關的,不會因為業務類的方法增多而逐漸龐大。
使代碼更易維護更易修改,實現自動化搬磚。
實際上,被代理的類不一定位于本機類,動態代理語法提供了一種抽象方式,被代理的類也可以位于遠程主機上,這也是RPC框架實現原理的一部分。
理解了動態代理的概念后不難發現,動態代理概念上有著這么幾個部分:
給調用者使用的代理類。在java中,我們發現動態代理提供的抽象天然契合面向接口編程,因此它也有可能是接口。
一個統一的處理函數,收集不同函數轉發過來的請求,可自定義處理邏輯集中處理。java中它可能會成為一個較獨立的部分,因此也可能是類。
java動態代理機制理解了概念,就不難理解java動態代理的機制了。下面來看看java動態代理機制如何代理一個本地對象。
代理接口首先看第一個部分,給調用者使用的代理類。在java動態代理機制中,這個角色只能是接口。我們定義一個整數運算接口:
interface NumberOperationInterface { int add(int a, int b); }代理處理器
再看第二個角色,統一的處理函數。在java中它的確是類,通過實現InvocationHandler接口定義。
class NumberOperationImpProxyHandler implements InvocationHandler { private Object proxied; public RealObjectProxyHandler(Object proxied) { this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.printf("調用函數%s ", method.getName()); return method.invoke(proxied, args); } }
由于我們的例子是代理本地對象,那么處理函數是需要被代理對象的信息??梢钥吹?,我們從構造函數中將被代理對象保存在該類中,即可從處理函數中訪問到。
在invoke函數中,對代理對象的所有方法的調用都被轉發至該函數處理。在這里可以靈活的自定義各種你能想到的邏輯。在上面的代碼中,我們使用反射調用被代理對象的同名方法實現。
被代理類由于我們的示例是代理本地對象,因此還需要一個被代理對象的類:
class NumberOperationImp implements NumerOperationInterface { @Override public int add(int a, int b) { return a + b; } }創建代理對象
好了,各個組成部分都定義完成。現在把它們組合起來:
public NumerOperationInterface wrap(NumerOperationInterface proxied) { return (NumerOperationInterface) Proxy.newProxyInstance( NumerOperationInterface.class.getClassLoader(), new Class[]{NumerOperationInterface.class}, new NumberOperationImpProxyHandler(proxied)); }
由于java提供的這個寫法實在是太啰嗦了,所以把它放入一個輔助函數中。
Proxy.newProxyInstance 方法能夠根據提供的接口和代理處理器創建代理對象。
java提供的寫法太啰嗦了,可以考慮使用Guake提供的輔助函數簡化下代碼。如下:
public NumerOperationInterface wrap(NumerOperationInterface proxied) { return Reflection.newProxy(NumerOperationInterface.class, new NumberOperationImpProxyHandler(proxied)); }
好了,現在調用下試試:
NumerOperationInterface proxied = new NumberOperationImp(); real = wrap(proxied); real.add(1, 2);總結
動態代理聽起來是代理模式的動態實現,可是結合上面的最終效果,不覺得這個叫做動態裝飾器更合適嗎?
動態代理的應用說完了動態代理的概念和實現機制,該看看使用動態代理有哪些應用。
應用一:代理模式/裝飾器模式的動態實現這個應用場景前面據已經提到過。
代理模式和裝飾器模式是編程當中很常用的技巧,用于提升代碼的靈活性和可擴展性。
傳統代理模式的實現方式比較暴力直接,需要將所有被代理類的所有方法都寫一遍,并且一個個的手動轉發過去。
在維護被代理類的同時,作為java碼工還需要同時維護代理類的相關代碼,實在是累心。
通過使用動態代理,動態代理能夠自動將代理類的相關方法轉發到被代理類,可以看到:
代理轉發的過程自動化了,實現自動化搬磚。
代理類的代碼邏輯和具體業務邏輯解耦,與業務無關。
應用二:實現AOP是的,利用動態代理也能實現AOP。仔細推演一下不能得出這個結論。我們知道:
動態代理提供了一種方式,能夠將分散的方法調用轉發到一個統一的處理函數處理。
AOP的實現需要能夠提供這樣一種機制,即在執行函數前和執行函數后都能執行自己定義的鉤子。
那么,首先使用動態代理讓代理類忠實的代理被代理類,然后處理函數中插入我們的自定義的鉤子。
之后讓代理類替換被代理類需要使用的場景,這樣,相當于對該類的所有方法定義了一個切面。
不過,使用動態代理實現AOP特別麻煩,啰嗦。這僅僅作為一個探討的思路,來說明動態代理這一通用概念可以實現很多特定技術。
實際使用中當然使用spring提供的AOP更為方便。
RPC即遠程過程調用,在分布式的網站架構中是一個非常重要的技術,目前現在流行的SOA架構,微服務架構,它們的核心原理之一就是RPC調用。
從概念上來說,RPC的概念是非常簡潔優美的。RPC方法的調用和普通的方法并無二異,調用者不需要操心具體的實現,這是抽象提供的威力。
實現上,它將函數調用方和函數的提供方分散在兩個不同的進程上,中間使用網絡通信來進行數據交互。
動態代理就是實現RPC的技術之一。只要理解了動態代理和RPC,我們很容易發現這樣一個事實:
RPC調用其實是對遠程另外一臺機器進程上的對象的代理。
仔細思考RPC調用的數據流流向,就能梳理出這樣的思路:
調用方調用本地的RPC代理方法,將參數提供給該方法。
不同的RPC代理方法被轉發到一個統一的處理中心,該處理中心知道調用的是那個函數,參數是什么。
該處理中心將調用的信息封裝打包,通過網絡發送給另外一個進程。
另外一個進程接受到調用進程發送過來的數據包。
該進程根據數據包中記錄的RPC調用信息,將調用分發給對應的被代理對象的對應方法去執行。
返回的話思路類似。
顯而易見,第二步,需要使用動態代理將分散的函數調用轉發到一個統一的處理中心;第五步,將統一收集來的調用信息分發給具體的函數執行,顯然使用反射做到這一點。
有了這個思路,通過利用動態代理,反射,和網絡編程技術,實現一個簡易版的RPC框架也就不難了。
考慮到本文是介紹動態代理的,關于RPC的細節實現有時間新開一篇博文分析。
總得來說,通過一定的思考,個人覺得動態代理的核心在于:將分散的對對象不同方法的調用轉發到一個同一的處理函數中來。
有了這個關鍵點,很多其它技術的實現需要借助于動態代理的這一個關鍵點實現,也因此動態代理也有著這么多的應用。
注:該文于2018-03-30撰寫于我的github靜態頁博客,現同步到我的segmentfault來。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71426.html
摘要:等之所以支持跨語言,是因為他們自己定義了一套結構化數據存儲格式,如的,用于編解碼對象,作為各個語言通信的中間協議。 前段時間覺得自己一直用別人的框架,站在巨人的肩膀上,也該自己造造輪子了 一時興起 就著手寫起了RPC框架 這里寫了系列博客拿給大家分享下 這篇是開篇的思路篇 項目最終的代碼放在了我的github上https://github.com/wephone/Me... 歡迎sta...
摘要:項目版本源碼在上一博文中跟大家講了的實現思路思路畢竟只是思路那么這篇就帶著源碼給大家講解下實現過程中的各個具體問題讀懂本篇需要的基本知識若尚未清晰請自行了解后再閱讀本文動態代理框架的基本使用的基本配置最終項目的使用如下調用端代碼及配置測試類 項目1.0版本源碼 https://github.com/wephone/Me... 在上一博文中 跟大家講了RPC的實現思路 思路畢竟只是思路...
摘要:是一個分布式服務框架,以及治理方案。手寫注意要點手寫注意要點基于上文中對于協議的理解,如果我們自己去實現,需要考慮哪些技術呢其實基于圖的整個流程應該有一個大概的理解?;谑謱憣崿F基于手寫實現理解了協議后,我們基于來實現一個通信框架。閱讀這篇文章之前,建議先閱讀和這篇文章關聯的內容。[1]詳細剖析分布式微服務架構下網絡通信的底層實現原理(圖解)[2][年薪60W的技巧]工作了5年,你真的理解N...
摘要:如問到是否使用某框架,實際是是問該框架的使用場景,有什么特點,和同類可框架對比一系列的問題。這兩個方向的區分點在于工作方向的側重點不同。 [TOC] 這是一份來自嗶哩嗶哩的Java面試Java面試 32個核心必考點完全解析(完) 課程預習 1.1 課程內容分為三個模塊 基礎模塊: 技術崗位與面試 計算機基礎 JVM原理 多線程 設計模式 數據結構與算法 應用模塊: 常用工具集 ...
摘要:動態代理能干嘛提供了另外一種實現接口的方式,不用也能實現接口。有了動態代理,中的網絡交互部分可以完全寫在框架中,對用戶來說編程更加方便。 靜態代理 public class TargetClass{ void method1() } public class ProxyClass{ private TargetClass target; public...
閱讀 3952·2021-11-11 10:58
閱讀 3321·2021-09-26 09:46
閱讀 1912·2019-08-30 15:55
閱讀 976·2019-08-30 13:52
閱讀 1944·2019-08-29 13:11
閱讀 3024·2019-08-29 11:27
閱讀 1517·2019-08-26 18:18
閱讀 2618·2019-08-23 14:17