1. 程式人生 > >Dubbo的RPC呼叫過程

Dubbo的RPC呼叫過程

Dubbo的RPC呼叫在客戶端觸發,配置檔案中定義:

<dubbo:reference id="xxxService" interface="xxx.xxx.Service"/>

這一行定義會為xxx.xxx.Service在本地生成一個遠端代理。在Dubbo中這個代理用com.alibaba.dubbo.common.bytecode.proxy0的例項表示。這個代理存在於本地可以像本地Bean一樣呼叫該服務,具體通訊過程由代理負責。

代理例項僅僅包含一個handler物件(實現InvokerInvocationHandler介面),handler中包含RPC呼叫核心介面Invoker < T >的實現。

public interface Invoker<T> extends Node {
    Class<T> getInterface();
    //呼叫過程的具體表示形式
    Result invoke(Invocation invocation) throws
    RpcException;
}

其中核心方法invoker(Invocation invocation)引數Invocation是一個呼叫過程的抽象,也是Dubbo框架的核心介面。

public interface Invocation { 
//呼叫的方法名稱
String getMethodName(); 
//呼叫方法的引數的型別列表 
Class<?>[] getParameterTypes(); //呼叫方法的引數列表 Object[] getArguments(); //呼叫時附加的資料,用 map 儲存 Map<String, String> getAttachments(); //根據 key 來獲取附加的資料 String getAttachment(String key); //getAttachment(String key)的拓展,支援預設值獲取 String getAttachment(String key, String defaultValue); //獲取真實的呼叫者實現 Invoker<?> getInvoker(); }

Invocation和Invoker相互依存,如果是RPC呼叫,Invocation的具體實現就是RPCInvocation,該方法異常時丟擲RpcException。

代理的handler例項中實現Invoker< T >的介面的是MockClusterInvoker,它僅僅是一個Invoker的包裝,只是用於Dubbo框架的mock功能,它的invoke方法實現:

public Result invoke(Invocation invocation) throws RpcException {
    Result result = null;
    /*這一行程式碼用於獲取該服務是否 供 mock 功能,如果 供,則 url 中會包 含 mock 關鍵字*/
    String value = directory.getUrl().getMethodParameter(invocation. getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
    if (value.length() == 0 || value.equalsIgnoreCase("false")){
        //沒有 mock 的過程,直接呼叫
        result = this.invoker.invoke(invocation);
    } else if (value.startsWith("force")) {
        //日誌記錄程式碼部分省略
        //force:direct mock,這裡用於處理強制 mock 的情況,不執行遠端呼叫 
        result = doMockInvoke(invocation, null);
    } else {
        //fail-mock,這裡處理失敗後 mock 的情況,即出現呼叫異常時執行 mock 
        try {
            result = this.invoker.invoke(invocation);               } catch (RpcException e) {
            if (e.isBiz()) { throw e;
            } else {
                //省略日誌記錄部分的程式碼
                //這裡執行 mockInvoke 的邏輯,在本地偽裝結果 
                result = doMockInvoke(invocation, e);
            } 
        }
}
return result; }

MockClusterInvoker實現來Invoker< T >介面但是沒有實現invoke的邏輯,只是包裝了一個Invoker的真實實現。如下:

public class MockClusterInvoker<T> implements Invoker<T>{
    private final Directory<T> directory ;
    private final Invoker<T> invoker;
    public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
        this.directory = directory;
        this.invoker = invoker; }
}

其中真實的Invoker實現包含了叢集容錯的功能,可知Dubbo的叢集容錯是在Invoker中實現的。

Dubbo預設的容錯實現FailoverClusterInvoker即失敗重試。在FailoverClusterInvoker的實現中核心方法invoke(Invocation invocation)繼承自AbstractClusterInvoker< T > 抽象類。AbstractClusterInvoker< T >中的invoke(Invocation invocation)方法的實現如下:

public Result invoke(final Invocation invocation) throws RpcException { 
    checkWheatherDestoried();
    LoadBalance loadbalance;
    List<Invoker<T>> invokers = list(invocation);
    if (invokers != null && invokers.size() > 0) {
        //這裡省略了獲取 loadbalance 例項的實現程式碼,具體思路就是用拓展類載入器根據配置載入 loadbalance 例項
    } else {
        loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).
getExtension(Constants.DEFAULT_LOADBALANCE);
    }
    RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); 
    return doInvoke(invocation, invokers, loadbalance);
}

list(invocation) 獲取 Invoker 的列表List< Invoker< T > >,這個列表可以對應到服務 供者的列表。其中,list(invocation)方法的實現程式碼如下:

protected List<Invoker<T>> list(Invocation invocation) throws RpcException { 
    List<Invoker<T>> invokers = directory.list(invocation);
    return invokers;
}

list(invocation)方法中用到關鍵的介面 Directory,它是 Dubbo 框架中用於封裝服務供者列表的一個數據結構。
Directory 的定義程式碼如下:

public interface Directory<T> extends Node {
    Class<T> getInterface();
    List<Invoker<T>> list(Invocation invocation) throws RpcException; 
    }

list(Invocation invocation)的引數是一個Invocation 物件表示的是一次(遠端)呼叫過程,list 方法返回一個呼叫者的列表 List< Invoker< T > >,directory 介面的例項例項是 RegistryDirectory類的物件 ,RegistryDirectory的list(invocation)方法繼承自 AbstractDirectory,具體實現如下:

public List<Invoker<T>> list(Invocation invocation) throws RpcException { 
    if (destroyed)
throw new RpcException("Directory already destroyed .url: "+ getUrl()); 
    //獲取呼叫列表
    List<Invoker<T>> invokers = doList(invocation);
    List<Router> localRouters = this.routers; // local reference
    if (localRouters != null && localRouters.size() > 0) {
        for (Router router: localRouters){ 
            try {
                if (router.getUrl() == null || router.getUrl(). getParameter(Constants.RUNTIME_KEY, true)) {
                    invokers = router.route(invokers, getConsumerUrl(), invocation);
                }
            } catch (Throwable t) {
                logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
            }
         }
    }
    return invokers;
}

每個 Consumer 會在本地快取(或者從註冊中心獲取)路由集合 List< Router > localRouters,然後判斷集合中的每一個路由規則是否可以對當前調 用進行過濾,如果路由規則符合當前呼叫,就對呼叫列表 List< Invoker< T > >進行 篩選,去除不符合的呼叫者。
Router 介面的定義程式碼如下:

public interface Router extends Comparable<Router> {
    //獲取當前路由的 url
    URL getUrl();
    //路由方法,對傳入的 List<Invoker<T>>進行路由篩選,篩選的條件包括 Invocation 物件和 consumer 的 url
    <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}

相關推薦

arm linux 系統呼叫過程

在Linux下系統呼叫是用軟中斷實現的,下面以一個簡單的open例子簡要分析一下應用層的open是如何呼叫到核心中的sys_open的。 t8.c 1: #include <stdio.h> 2: #include <sys/types.h> 3:

Java中的方法呼叫過程分析

假設呼叫x.f(args),隱式引數x宣告為類C的一個例項物件: 1.編譯器檢視物件的宣告型別和方法名。例如,可能存在方法f(int)和方法f(String)。編譯器將會一一列舉出所有該類中名為f的方法和其超類中訪問屬性為public且名為f的方法。 2.編譯器將檢視呼叫方法時提供的引數型別

WebService—CXF整合Spring實現介面釋出和呼叫過程

CXF整合Spring實現介面釋出 釋出過程如下: 1、引入jar包(基於maven管理) <dependency> <groupId>org.apache.cxf</groupId> <artifactId>

Spring Cloud微服務的簡單組成和呼叫過程

學習微服務的過程中,很多東西都會忘,所以就畫了一個微服務的圖,其實之前我也畫過微服務的圖,但是沒有這個詳細,希望能幫到正在開始學習微服務的人吧!       其實微服務很簡單就像你去足療店一樣,你不知道怎麼去,第一次,怎麼辦,你求助你的朋友,你的朋友經常去,所以你的

函式的呼叫過程詳解———棧幀的建立和銷燬

●回顧內容: 函式的定義:函式是一個程式中的部分程式碼,由一個或多個語句組成,它的功能是實現某些特定的任務。函式相對於其他程式碼來說具備相對的獨立性。 函式的呼叫:在某個函式內部,使用另一個函式來完成相關的任務,這個過程叫做函式呼叫。 那麼函式是如何呼叫的呢?分析一段簡單的程式碼:

高階語言反彙編程式的函式呼叫過程

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

【18.7.27】函式呼叫過程的深度理解(棧幀)

函式可以大大減少我們程式的程式碼量,使程式碼寫起來更加的簡潔,使程式碼思路更加清晰。是我們程式猿在編寫程式碼時必不可少的。 那麼函式的呼叫過程就非常的重要,今天讓我們來從一個深的角度去了解一下函式的呼叫過程。 函式的呼叫過程也可以叫做棧幀 棧幀的定義是:棧幀也叫過程活動記錄,

dubbo原始碼理解(2)消費者呼叫過程

又過了很久才敢寫。自己也在反覆看,consumer在啟動時是如何建立代理並注入的呢? 在第一篇 我寫了一些bean的載入過程。這個過程也是包含在啟動過程中的。 one、spring 載入dubbo檔案,開始解析consumer 配置檔案。目的 就是注入。但這時候還沒有物件可以注入。只是有這個

dubbo的服務呼叫過程

服務消費的過程:referenceConfig類的init方法呼叫Protocol的refer方法,生成invoker例項,然後把Invoker轉換為客戶端需要的介面。 2、原始碼解析 dubbo的消費端初始化在ReferenceConfig的get()方法 public

Dubbo原始碼理解(3) 消費者呼叫過程

小弟一直苦思 consumer 與provider 到底是怎麼通訊的呢,與是從網上找了一篇,覺得寫得很靠譜。自己就算總結,也未必有這個好,所以記錄下來!! 消費者呼叫流程涉及到消費者端和生產者端的互動,所以將分為三個部分來講解,分別是 -消費者發起呼叫請求 -生產者響應呼叫請求 -消費者獲取呼叫

追蹤shell呼叫過程-strace--效能優化與測試

追蹤shell呼叫過程-strace–效能優化與測試 strace可以追蹤shell呼叫的過程。 可以用來優化相關內容 具體效能優化與測試轉自https://blog.csdn.net/z1134145881/article/details/52079836 Mark

iOS進階—Runtime:OC方法底層呼叫過程

GitHub參考 PS:參考GitHub分享的Runtime002程式碼 iOS進階—目錄 OC方法底層呼叫過程 如果檢視OC的底層呼叫過程,我們需要藉助clang工具 使用終端 cd 專案目錄 clang -rewrite-objc main.m 會生成

深入理解C語言的函式呼叫過程

    本文主要從程序棧空間的層面複習一下C語言中函式呼叫的具體過程,以加深對一些基礎知識的理解。     先看一個最簡單的程式:   點選(此處)摺疊或開啟  /*test.c*/ #include <stdio.h> int foo1(

Dubbo呼叫過程監控

MonitorFilter 主要對呼叫過程進行監控, public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { if(invoker.ge

C語言函式呼叫過程的彙編分析

轉自:   http://www.cnblogs.com/xiaojianliu/articles/8733560.html   下面一段C程式: int bar(int c, int d) { int e = c + d; return e; }

android中的跨程序通訊的實現(一)——遠端呼叫過程和aidl

android在設計理念上強調元件化,元件之間的依賴性很小。我們往往發一個intent請求就可以啟動另一個應用的activity,或者一個你不知道在哪個程序的service,或者可以註冊一個廣播,只要有這個事件發生你都可以收到,又或者你可以查詢一個contentProvider獲得你想要的資料,這其

C++ 函式呼叫過程中棧的變化解析

“ 走好選擇的路,別選擇好走的路,你才能擁有真正的自己。” There you go again! I'll back you up! 記錄下函式呼叫的情況~ 函式呼叫的另一個詞語表示叫作 過程。一個過程呼叫包括將資料和控制從程式碼的一部分傳遞到另一部分。

ARM函式呼叫過程分析

1.  ARM的棧幀     先來看看ARM的棧幀佈局圖:          上圖描述的是ARM的棧幀佈局方式,main stack frame為呼叫函式的棧幀,func1 stack frame為當前函式(被呼叫者)的棧幀,棧底在高地址,棧向下增長。圖中FP就是棧基址,

c語言函式呼叫過程中棧的工作原理理解

差不多每個程式設計師都知道,函式呼叫過程,就是層層入棧出棧的過程。 那麼這個過程中的詳細的細節是什麼樣子的呢? 閱讀了以下幾篇文章之後,對整個過程基本理解了: C函式呼叫過程原理及函式棧幀分析 閱讀經典——《深入理解計算機系統》04 函式返回值與棧 針對自己的理解,做個記錄:

Oracle中建立儲存過程呼叫過程(一)

1、定義         所謂儲存過程(Stored Procedure),就是一組用於完成特定資料庫功能的SQL語句集,該SQL語句集經過 編譯後儲存在資料庫系統中。在使用時候,使用者通過指定已經定義的儲存過程名字並給出相應的儲存過程引數 來呼叫並執行