理解 Dubbo 服務引用 原

 

dubbo 服務引用過程

        dubbo 的使用過程中消費者端會依賴服務端提供的 api 包(接口 jar 包) , 這些 api 包中只含有服務的 Interface 的 class 文件 , 在進行服務調用的時候使用 Interface 的一個引用,就可以進行遠程的調用了,因爲 dubbo 在客戶端動態的生成了一個該 Interface 類型的代理類。在這個代理類中封裝了遠程服務調用的組件。獲取這個 Interface 類型的代理對象的實例通過 spring IOC 容器 ,自動注入的方式或者通過 getBean 的方式。服務引用的入口代碼:

com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
com.alibaba.dubbo.config.spring.schema.DubboBeanDefinitionParser
com.alibaba.dubbo.config.spring.ReferenceBean

ReferenceBean 實現了 spring 的 FactoryBean 接口 , 該接口有一個 T getObject() 函數 ,dubbo 服務引用的開端就是在實現的這個 getObject() 函數中。當對任意服務 Interface 進行自動注入或者 getBean 獲取時,就會觸發服務的引用過程。    

               

        服務引用分爲和服務提供者在同一個 JVM 實例中和在不同的 JVM 引用,和服務提供者在同一 JVM 實例中引用不會打開網絡連接,同一 JVM 實例內調用不需要經過網絡傳輸過程。在和服務提供者不同的 JVM 實例內引用時就必須打開網絡連接,否則無法調用遠程服務。

        和服務提供者在不同 JVM 實例中引用,首先消費者要去註冊中心進行註冊, 接下來訂閱所引用的服務。當服務提供者接收到消費者的訂閱消息後會去註冊中心查找已經註冊的所有服務 , 然後匹配哪一個服務是當前消費者正在訂閱的服務 , 如果匹配成功了就會通過註冊中心通知消費者找到了消費者訂閱的服務,消費者接收到註冊中心發送的匹配服務成功消息後 , 會調用消費者註冊的訂閱通知監聽 (NotifyListener), NotifyListener 中的 notify 會被調用 。 dubbo 提供了一個 RegistryDirectory 實現了 NotifyListener 接口 , 在 notify 函數中去刷新 Invoker (refreshInvoker) 。這時候會去創建一個新的 Invoker , 創建的這個 Invoker 還是和之前博客中討論過的創建 Invoker 的過程一樣, Invoker 會被 Filter 、 Listener 包裝。在創建這個 Invoker 的過程中也會打開網絡連接。

                   

        這裏使用的註冊中心是 multicast 。 zookeeper , redis 註冊中心的具體實現方式不同。如果在消費者服務引用的過程中,服務提供者沒有正常啓動的話,是不會去進行打開網絡連接操作的,如果在消費者連接提供者的過程中提供者掛掉了拋出異常 RemotingException  。

 

打開網絡連接

        消費者在引用服務的過程中如果和提供者不在同一 JVM 實例內,需要去打開網絡連接,來和服務提供者進行網絡通信。打開網絡連接的過程和服務端在網絡中暴露服務的順序一致 Transporter , Exchanger , ExchangeClient 可選的實現有 NettyClient (默認) , MinaClient , GrizzlyClient 。消費者建立客戶端打開網絡連接之後要和所訂閱的服務端建立連接。Interface 引用 , Invoker  , ExchangeClient  , Provider 之間的關係大致是這樣:

            

        每一個服務引用都可能對應多個 Invoker , 每一個 Invoker 指向了一個 Provider ,消費者內部會開啓多個客戶端與提供者開啓的一個服務端進行通信。當使用服務引用調用服務時,就可以在多個 Invoker 之間進行負載均衡。如果每個 Invoker 只有一個 Client,這樣稱爲共享連接。每一個服務引用也可以使用多個網絡連接,在 <dubbo:reference connections="3" /> 進行配置 , 默認使用共享網絡連接。

 

創建服務存根接口的代理對象

        通過 ProxyFactory 擴展點 getProxy 來獲取一個代理對象的實例 ,dubbo 默認使用的是 JavassistProxyFactory 擴展 , 動態的生成一個代理類和這個代理類的實例對象 。我的 Interface 代碼 :

package net.j4love.dubbo.quickstart.provider;

public interface DemoService {

    String echoWithCurrentTime(String src);
}

        生成的接口代理類代碼 :

package com.alibaba.dubbo.common.bytecode;

public class com.alibaba.dubbo.common.bytecode.proxy0
implements interface net.j4love.dubbo.quickstart.provider.DemoService ,
    interface com.alibaba.dubbo.rpc.service.EchoService {

    // 存儲的是所有實現的接口中的 method
    public static java.lang.reflect.Method[] methods;

    private java.lang.reflect.InvocationHandler handler;

    public proxy0(java.lang.reflect.InvocationHandler $1) {
        handler=$1;
    }

    public java.lang.String echoWithCurrentTime(java.lang.String $1) {
        Object[] args = new Object[1];
        args[0] = ($w)$1;
        Object ret = handler.invoke(this, methods[0], args);
        return (java.lang.String)ret;
    }

    public java.lang.Object $echo(java.lang.Object $1) {
        Object[] args = new Object[1];
        args[0] = ($w)$1;
        Object ret = handler.invoke(this, methods[1], args);
        return (java.lang.Object)ret;
    }
}

         生成的 com.alibaba.dubbo.common.bytecode.Proxy 的實現類代碼 :

public class com.alibaba.dubbo.common.bytecode.Proxy0 extends
com.alibaba.dubbo.common.bytecode.Proxy {
    public Proxy0() {}

    public Object newInstance(java.lang.reflect.InvocationHandler h) {
        return new com.alibaba.dubbo.common.bytecode.proxy0($1);
    }
}

        數字 0 是自增生成的 , 從 0 開始自增。

 

回聲測試

        所有的動態生成的引用接口代理類都實現了 com.alibaba.dubbo.rpc.service.EchoService 這個接口,獲取到的引用可以強制轉換成 EchoService  調用 $echo 函數來測試服務是否可用。

 

泛化調用

        泛化調用是用 interface com.alibaba.dubbo.rpc.service.GenericService 接口來替代自定義的服務接口,通過  $invoke 函數來調用遠程服務 , 這種方式適用於消費者端本地沒有服務提供者端的接口 jar 包時,但是卻知道接口的全名稱 , 接口全名稱是必須知道的因爲要靠這個名稱去註冊中心尋找是否有註冊的服務提供者。泛化調用只需要進行配置就可使用  , generic 設置爲 true:

<dubbo:reference id="demoService"
                     version="1.0.0"
                     generic="true"
                     interface="net.j4love.dubbo.quickstart.provider.DemoService" />

 

 

 

 

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