dubbo 學習(二)-- 簡單實現遠程方法調用

參考博客

前言

在學習dubbo過程中,經常有“我要學習什麼的想法”,經常有看完一部分不知道後面要幹嘛的時候。總的來說感覺自己缺少“dubbo能幹什麼?”的明確答案,所以在學習的時候就缺乏學習路線,這也跟自己長期的學習習慣有關:我要學習A技能,上網搜索 “A技能教程”或者“從零開始學A”。這樣自己的學習完全依賴他人的總結,所以導致學習的成果同樣依賴博客的質量,這就是高耦合啊同學們!!!我的學習質量爲什麼要依賴他人的學習成果。希望從今天開始改變自己的學習方式,從dubbo開始.

RPC

dubbo是一個RPC框架,在學習這個框架之前我們需要先明白什麼是RPC,爲什麼需要RPC框架,怎麼實現RPC框架(what why how)。

RPC是Remote Procedure Call,字面意思就是“遠程過程調用”,翻譯爲“遠程程序調用”可能更符合我們程序員。它的功能就是可以在A機器上訪問B機器上的方法。

那麼爲什麼需要RPC,隨着業務量擴大,單機系統拆分成集羣,爲了維護性和高可用性的系統服務化,都需要RPC來實現。那麼現在對RPC有了大致瞭解,也知道爲什麼要用RPC了,但是RPC框架是什麼鬼,它有啥用?那麼這就要從如何實現RPC講起了。

RPC框架結構

我們先來想想如何實現一次遠程調用,既然是遠程調用,首先肯定要處理網絡問題,我們可以使用現有協議比如http,或者我們自定義協議;網絡問題解決後就要傳輸數據了,客戶端調用服務端方法,需要知道對方地址(ip),調用的方法地址(接口名稱,方法名稱),參數等。傳輸這些數據之前就需要對數據進行序列化操作,相對的接收數據後需要反序列化。盜用大佬的一副圖片
在這裏插入圖片描述
以及大佬說的:
1)服務消費方(client)調用以本地調用方式調用服務;

2)client stub接收到調用後負責將方法、參數等組裝成能夠進行網絡傳輸的消息體;

3)client stub找到服務地址,並將消息發送到服務端;

4)server stub收到消息後進行解碼;

5)server stub根據解碼結果調用本地的服務;

6)本地服務執行並將結果返回給server stub;

7)server stub將返回結果打包成消息併發送至消費方;

8)client stub接收到消息,並進行解碼;

9)服務消費方得到最終結果。
RPC的目標就是要2~8這些步驟都封裝起來,讓用戶對這些細節透明。

後面我會按照大佬的邏輯實現一個簡單rpc框架。

簡單通信

首先是兩個項目通過socket的通信,相信大家之前都寫過類似的輪子,這裏就不貼代碼;

特定服務調用

既然兩個服務可以通過網絡互相通信,那麼我們完全可以在客戶端發送需要調用的服務類信息、方法信息、參數等。
調用的服務

public interface DemoService {

    String sayHi(String name);
}

客戶端調用代碼如下

public class ClientApp {

    public static void main(String[] args) {

        try {
            RPCClient.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        DemoService service = ServiceFactory.createService("demo");
        System.out.println(service.sayHi("haha"));
    }
}

start是啓動了網絡訪問;後面我們需要假裝給接口一個實現類,然後由這個實現類執行目標方法。
根據我們前面的理論,我們需要一個代理類來假裝實現類,完成訪問遠端方法的責任,所以這裏我們使用一個靜態代理實現(爲了簡單)。

public class DemoServiceProxy implements DemoService {

    public String sayHi(String name){

        String msg = "com.tiger.dubbo.api.DemoService-sayHi-java.lang.String-" + name;
        try {
            return (String) RPCClient.sendMsg(msg);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

代理類非常簡單;msg中的信息是傳給服務端的,服務端會解析信息中的內容做相應的處理,這裏我們簡單處理,定義參數間用“-”隔開,第一個爲服務類名稱,第二個爲方法名,第三個爲參數類,第四個爲參數值(對,只支持一個參數),這就相當於一個簡單的協議。

服務端這邊也很簡單,根據協議解析信息,並做處理代碼如下:

public static Object handleMsg(String msg)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {

        String[] msgArr = msg.split("-");
        String klassName = msgArr[0];
        if ("com.tiger.dubbo.api.DemoService".equals(klassName))
            klassName = "com.togo.service.DemoServiceImpl";
        Class klass = Class.forName(klassName);
        Class param = Class.forName(msgArr[2]);
        Method method = klass.getMethod(msgArr[1], param);

        return method.invoke(klass.newInstance(), msgArr[3]);
    }

看到我的實現類獲取方式有沒有某個部位突然發緊。Orz

根據我們的協議,一些信息,並執行對應方法,將信息返回。

至此有翔以來最吊的rpc完成了~~撒花~~

當然後續會繼續完善,並對照dubbo等框架學習~作者還是很認真的 ~.~

完整代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章