中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Java 動態(tài)代理及 RPC 框架介紹

2018-08-01    來源:importnew

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

所謂動態(tài)代理,指的是語言提供的一種語法,能夠?qū)ο笾胁煌椒ǖ恼{(diào)用重定向到一個(gè)統(tǒng)一的處理函數(shù)中來。
python重寫__getattr__函數(shù)能夠做到這一點(diǎn),就連世界上最好的語言也提供稱為魔術(shù)方法的__call。
這種語法除了能更好的實(shí)現(xiàn)動態(tài)代理外,還是RPC框架實(shí)現(xiàn)原理的一部分。

1. 動態(tài)代理是什么

動態(tài)代理提供一種抽象,能夠?qū)ο笾胁煌椒ǖ恼{(diào)用重定向到一個(gè)統(tǒng)一的處理函數(shù),做自定義的邏輯處理。
但是對于調(diào)用者,對此毫無察覺,就好像調(diào)用的方法是用傳統(tǒng)方式實(shí)現(xiàn)的一般。

這種語法,在java中被稱為動態(tài)代理。之所以叫做動態(tài)代理,是因?yàn)樗鼙苊鈧鹘y(tǒng)代理模式實(shí)現(xiàn)中人工一個(gè)一個(gè)的將java函數(shù)轉(zhuǎn)發(fā)過去,
而是能夠讓代碼自動做到這一點(diǎn),這樣代理類的代碼是和業(yè)務(wù)無關(guān)的,不會因?yàn)闃I(yè)務(wù)類的方法增多而逐漸龐大。
使代碼更易維護(hù)更易修改,實(shí)現(xiàn)自動化搬磚。

實(shí)際上,被代理的類不一定位于本機(jī)類,動態(tài)代理語法提供了一種抽象方式,被代理的類也可以位于遠(yuǎn)程主機(jī)上,這也是RPC框架實(shí)現(xiàn)原理的一部分。

理解了動態(tài)代理的概念后不難發(fā)現(xiàn),動態(tài)代理概念上有著這么幾個(gè)部分:

  1. 給調(diào)用者使用的代理類。在java中,我們發(fā)現(xiàn)動態(tài)代理提供的抽象天然契合面向接口編程,因此它也有可能是接口。
  2. 一個(gè)統(tǒng)一的處理函數(shù),收集不同函數(shù)轉(zhuǎn)發(fā)過來的請求,可自定義處理邏輯集中處理。java中它可能會成為一個(gè)較獨(dú)立的部分,因此也可能是類。

2. java動態(tài)代理機(jī)制

理解了概念,就不難理解java動態(tài)代理的機(jī)制了。下面來看看java動態(tài)代理機(jī)制如何代理一個(gè)本地對象。

2.1. 代理接口

首先看第一個(gè)部分,給調(diào)用者使用的代理類。在java動態(tài)代理機(jī)制中,這個(gè)角色只能是接口。我們定義一個(gè)整數(shù)運(yùn)算接口:

interface NumberOperationInterface {
    int add(int a, int b);
}

2.2. 代理處理器

再看第二個(gè)角色,統(tǒng)一的處理函數(shù)。在java中它的確是類,通過實(shí)現(xiàn)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("調(diào)用函數(shù)%s\n", method.getName());
        return method.invoke(proxied, args);
    }
}
  1. 由于我們的例子是代理本地對象,那么處理函數(shù)是需要被代理對象的信息?梢钥吹剑覀儚臉(gòu)造函數(shù)中將被代理對象保存在該類中,即可從處理函數(shù)中訪問到。
  2. invoke函數(shù)中,對代理對象的所有方法的調(diào)用都被轉(zhuǎn)發(fā)至該函數(shù)處理。在這里可以靈活的自定義各種你能想到的邏輯。在上面的代碼中,我們使用反射調(diào)用被代理對象的同名方法實(shí)現(xiàn)。

2.3. 被代理類

由于我們的示例是代理本地對象,因此還需要一個(gè)被代理對象的類:

class NumberOperationImp implements NumerOperationInterface {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
}

2.4. 創(chuàng)建代理對象

好了,各個(gè)組成部分都定義完成,F(xiàn)在把它們組合起來:

public NumerOperationInterface wrap(NumerOperationInterface proxied) {
    return (NumerOperationInterface) Proxy.newProxyInstance(
        NumerOperationInterface.class.getClassLoader(),
        new Class[]{NumerOperationInterface.class},
        new NumberOperationImpProxyHandler(proxied));
}
  1. 由于java提供的這個(gè)寫法實(shí)在是太啰嗦了,所以把它放入一個(gè)輔助函數(shù)中。
  2. Proxy.newProxyInstance?方法能夠根據(jù)提供的接口和代理處理器創(chuàng)建代理對象。

java提供的寫法太啰嗦了,可以考慮使用Guake提供的輔助函數(shù)簡化下代碼。如下:

public NumerOperationInterface wrap(NumerOperationInterface proxied) {
    return Reflection.newProxy(NumerOperationInterface.class, new NumberOperationImpProxyHandler(proxied));
}

好了,現(xiàn)在調(diào)用下試試:

NumerOperationInterface proxied = new NumberOperationImp();
real = wrap(proxied);
real.add(1, 2);

2.5. 總結(jié)

動態(tài)代理聽起來是代理模式的動態(tài)實(shí)現(xiàn),可是結(jié)合上面的最終效果,不覺得這個(gè)叫做動態(tài)裝飾器更合適嗎?

3. 動態(tài)代理的應(yīng)用

說完了動態(tài)代理的概念和實(shí)現(xiàn)機(jī)制,該看看使用動態(tài)代理有哪些應(yīng)用。

3.1. 應(yīng)用一:代理模式/裝飾器模式的動態(tài)實(shí)現(xiàn)

這個(gè)應(yīng)用場景前面據(jù)已經(jīng)提到過。
代理模式和裝飾器模式是編程當(dāng)中很常用的技巧,用于提升代碼的靈活性和可擴(kuò)展性。
傳統(tǒng)代理模式的實(shí)現(xiàn)方式比較暴力直接,需要將所有被代理類的所有方法都寫一遍,并且一個(gè)個(gè)的手動轉(zhuǎn)發(fā)過去。
在維護(hù)被代理類的同時(shí),作為java碼工還需要同時(shí)維護(hù)代理類的相關(guān)代碼,實(shí)在是累心。

通過使用動態(tài)代理,動態(tài)代理能夠自動將代理類的相關(guān)方法轉(zhuǎn)發(fā)到被代理類,可以看到:

  1. 代理轉(zhuǎn)發(fā)的過程自動化了,實(shí)現(xiàn)自動化搬磚。
  2. 代理類的代碼邏輯和具體業(yè)務(wù)邏輯解耦,與業(yè)務(wù)無關(guān)。

3.2. 應(yīng)用二:實(shí)現(xiàn)AOP

是的,利用動態(tài)代理也能實(shí)現(xiàn)AOP。仔細(xì)推演一下不能得出這個(gè)結(jié)論。我們知道:

  1. 動態(tài)代理提供了一種方式,能夠?qū)⒎稚⒌姆椒ㄕ{(diào)用轉(zhuǎn)發(fā)到一個(gè)統(tǒng)一的處理函數(shù)處理。
  2. AOP的實(shí)現(xiàn)需要能夠提供這樣一種機(jī)制,即在執(zhí)行函數(shù)前和執(zhí)行函數(shù)后都能執(zhí)行自己定義的鉤子。

那么,首先使用動態(tài)代理讓代理類忠實(shí)的代理被代理類,然后處理函數(shù)中插入我們的自定義的鉤子。
之后讓代理類替換被代理類需要使用的場景,這樣,相當(dāng)于對該類的所有方法定義了一個(gè)切面。

不過,使用動態(tài)代理實(shí)現(xiàn)AOP特別麻煩,啰嗦。這僅僅作為一個(gè)探討的思路,來說明動態(tài)代理這一通用概念可以實(shí)現(xiàn)很多特定技術(shù)。
實(shí)際使用中當(dāng)然使用spring提供的AOP更為方便。

3.3. 應(yīng)用三:實(shí)現(xiàn)RPC

RPC即遠(yuǎn)程過程調(diào)用,在分布式的網(wǎng)站架構(gòu)中是一個(gè)非常重要的技術(shù),目前現(xiàn)在流行的SOA架構(gòu),微服務(wù)架構(gòu),它們的核心原理之一就是RPC調(diào)用。

從概念上來說,RPC的概念是非常簡潔優(yōu)美的。RPC方法的調(diào)用和普通的方法并無二異,調(diào)用者不需要操心具體的實(shí)現(xiàn),這是抽象提供的威力。
實(shí)現(xiàn)上,它將函數(shù)調(diào)用方和函數(shù)的提供方分散在兩個(gè)不同的進(jìn)程上,中間使用網(wǎng)絡(luò)通信來進(jìn)行數(shù)據(jù)交互。

動態(tài)代理就是實(shí)現(xiàn)RPC的技術(shù)之一。只要理解了動態(tài)代理和RPC,我們很容易發(fā)現(xiàn)這樣一個(gè)事實(shí):
RPC調(diào)用其實(shí)是對遠(yuǎn)程另外一臺機(jī)器進(jìn)程上的對象的代理。

仔細(xì)思考RPC調(diào)用的數(shù)據(jù)流流向,就能梳理出這樣的思路:

  1. 調(diào)用方調(diào)用本地的RPC代理方法,將參數(shù)提供給該方法。
  2. 不同的RPC代理方法被轉(zhuǎn)發(fā)到一個(gè)統(tǒng)一的處理中心,該處理中心知道調(diào)用的是那個(gè)函數(shù),參數(shù)是什么。
  3. 該處理中心將調(diào)用的信息封裝打包,通過網(wǎng)絡(luò)發(fā)送給另外一個(gè)進(jìn)程。
  4. 另外一個(gè)進(jìn)程接受到調(diào)用進(jìn)程發(fā)送過來的數(shù)據(jù)包。
  5. 該進(jìn)程根據(jù)數(shù)據(jù)包中記錄的RPC調(diào)用信息,將調(diào)用分發(fā)給對應(yīng)的被代理對象的對應(yīng)方法去執(zhí)行。
  6. 返回的話思路類似。

顯而易見,第二步,需要使用動態(tài)代理將分散的函數(shù)調(diào)用轉(zhuǎn)發(fā)到一個(gè)統(tǒng)一的處理中心;第五步,將統(tǒng)一收集來的調(diào)用信息分發(fā)給具體的函數(shù)執(zhí)行,顯然使用反射做到這一點(diǎn)。
有了這個(gè)思路,通過利用動態(tài)代理,反射,和網(wǎng)絡(luò)編程技術(shù),實(shí)現(xiàn)一個(gè)簡易版的RPC框架也就不難了。
考慮到本文是介紹動態(tài)代理的,關(guān)于RPC的細(xì)節(jié)實(shí)現(xiàn)有時(shí)間新開一篇博文分析。

4. 最后

總得來說,通過一定的思考,個(gè)人覺得動態(tài)代理的核心在于:將分散的對對象不同方法的調(diào)用轉(zhuǎn)發(fā)到一個(gè)同一的處理函數(shù)中來。

有了這個(gè)關(guān)鍵點(diǎn),很多其它技術(shù)的實(shí)現(xiàn)需要借助于動態(tài)代理的這一個(gè)關(guān)鍵點(diǎn)實(shí)現(xiàn),也因此動態(tài)代理也有著這么多的應(yīng)用。

標(biāo)簽: ssl 代碼 通信 網(wǎng)絡(luò)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:SpringBoot | 第四章 :日志管理

下一篇:SpringBoot | 第三章:springboot配置詳解