11、dubbo源碼分析 之 服務引用

原文地址:http://www.carlzone.cn/dubbo/11-dubbo-consuer-ref/

在使用 dubbo 的時候,我們對於遠程服務調用是無感知的。當需要調用遠程服務的時候我們只需要進行以下配置,就可以像本地調用的方式調用遠程服務:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <dubbo:application name="demo-consumer"/>
    <dubbo:registry address="zookeeper://localhost:2181"/>
    <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService"/>
</beans>

下面的圖片是 dubbo 官方服務消費者消費一個服務的詳細過程的圖:

這裏寫圖片描述

dubbo 的服務引用其實就是把上面的配置解析成 dubbo 框架的 ReferenceConfig(接口引用配置類),然後調用ReferenceConfig類的 init 方法調用 Protocol 的 refer方法生成 Invoker 實例(如上圖中的紅色部分),這是服務消費的關鍵。接下來把Invoker轉換爲客戶端需要的接口(如:HelloService)。

關於每種協議如 RMI/Dubbo/Web service 等它們在調用 refer 方法生成 Invoker 實例。最後調用 ProxyFactory#getProxy(Invoker)生成遠程暴露服務接口的代理對象。

那麼 dubbo 在框架內部是如何實現的呢?下面我們來具體分析一下它的源碼實現。

我們在 xml 裏面配置 dubbo 服務的引用,其實是 dubbo 實現了自定義命名空間的方式來集成 Spring 框架。這樣通過 Spring 的 IOC 特性可以很方便的創建 dubbo 的配置對象。

這裏寫圖片描述

對於 <reference: /> 標籤 Spring 會把它解析成 ReferenceBean 對象,並且這個對象是一個 FactoryBean。所以當我們通過 Spring 依賴注入這個對象的時候會調用 ReferenceBean#getObject 獲取接口對象的實例。它會把參數解析到一個 Map 中,然後根據其中的參數創建服務引用的代理對象。Map 裏面的值大概如下所示:

這裏寫圖片描述

1、ReferenceConfig#createProxy

1、loadRegistries()加載註冊中心配置,因爲 dubbo 支持多配置中心,所以返回 URL 的集合。 2、便利註冊中心 List<URL>集合:加載監控中心 URL,如果配置了監控中心就在註冊 URL 加上monitor;把服務引用的配置參數添加到註冊 URL 的 refer參數上。 3、Protocol#refer引用遠程服務,通過註冊中心 URL 與 接口 Class 創建 Invoker 調用對象。 4、proxyFactory.getProxy(invoker);通過代理工廠創建遠程服務代理返回給使用者。

2、Procotol#refer

和服務暴露一樣,consumer 端進行服務調用的時候,可以對 dubbo 框架進行擴展:com.alibaba.dubbo.rpc.ExporterListenercom.alibaba.dubbo.rpc.Filter。所以獲取到的 Procotol 實例的結構是:

  • ProtocolListenerWrapper
    • ProtocolFilterWrapper
      • RegistryProtocol

1、RegistryFactory#getRegistry獲取到 zookeeper 註冊中心,和服務暴露獲取註冊中心的邏輯一樣。 2、創建註冊服務目錄 RegistryDirectory 3、註冊服務消費者 URL 到 zookeeper,其實就是創建 zookeeper 的節點,和服務端發佈類似。

/dubbo/com.alibaba.dubbo.demo.DemoService/consumers
/consumer%3A%2F%2F192.168.20.1%2Fcom.alibaba.dubbo.demo.DemoService%3Fapplication%3Ddemo-consumer%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.0%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D3808%26qos.port%3D33333%26side%3Dconsumer%26timestamp%3D1522590290256

4、訂閱 zookeeper 以下結點,當服務發生變更時,銷燬無效的 Invoke.刷新 RegistryDirectory 中的Map<String, List<Invoker<T>>> methodInvokerMap對象。

  • /dubbo/com.alibaba.dubbo.demo.DemoService/providers
  • /dubbo/com.alibaba.dubbo.demo.DemoService/configurators
  • /dubbo/com.alibaba.dubbo.demo.DemoService/routers

5、調用cluster#join(directory) 合併 invoker 創建並提供集羣 failover (故障轉移)調用策略

  • cluster#join(directory)//加入集羣路由
    • ExtensionLoader#getExtensionLoader(Cluster.class).getExtension("failover");
      • MockClusterWrapper#join
        • this.cluster#join(directory)
          • FailoverCluster#join
            • return new FailoverClusterInvoker<T>(directory)

3、DubboProtocol#refer

1、通過 接口Class對象、服務URL、ExchangeClient和Set<Invoker<?>> invokers創建 DubboInvoke 對象 2、獲取 ExchangeClient 數據交換客戶端 HeaderExchangeClient,並創建心跳連接。默認是創建 Netty 客戶端用來調用暴露的遠程調用。 3、將創建的 invoker (服務調用者)返回給目錄服務,用來刷新 RegistryDirectory 中的Map<String, List<Invoker<T>>> methodInvokerMap對象。

4、ProxyFactory#getProxy

通過代理工廠創建服務引用接口的代理對象,用於訪問暴露的遠程服務。

1、根據 dubbo SPI 機制默認獲取到 JavassistProxyFactory 對象 2、通過上面獲取到的 Invoke對象以及引用的遠程服務接口 + dubbo 裏面的 EchoService 調用AbstractProxyFactory#getProxy(Invoker<T>, Class<?>[])獲取到代理對象。 3、使用 JDK 裏面的 InvocationHandler 對象代理遠程暴露服務 Invoke 調用對象創建遠程暴露服務接口代理對象。

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