11、dubbo源碼分析 之 服務(wù)引用

在使用 dubbo 的時候,我們對于遠(yuǎn)程服務(wù)調(diào)用是無感知的。當(dāng)需要調(diào)用遠(yuǎn)程服務(wù)的時候我們只需要進(jìn)行以下配置,就可以像本地調(diào)用的方式調(diào)用遠(yuǎn)程服務(wù):

<?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 官方服務(wù)消費(fèi)者消費(fèi)一個服務(wù)的詳細(xì)過程的圖:

這里寫圖片描述

dubbo 的服務(wù)引用其實(shí)就是把上面的配置解析成 dubbo 框架的 ReferenceConfig(接口引用配置類),然后調(diào)用ReferenceConfig類的 init 方法調(diào)用 Protocolrefer方法生成 Invoker 實(shí)例(如上圖中的紅色部分),這是服務(wù)消費(fèi)的關(guān)鍵。接下來把Invoker轉(zhuǎn)換為客戶端需要的接口(如:HelloService)。

關(guān)于每種協(xié)議如 RMI/Dubbo/Web service 等它們在調(diào)用 refer 方法生成 Invoker 實(shí)例。最后調(diào)用 ProxyFactory#getProxy(Invoker)生成遠(yuǎn)程暴露服務(wù)接口的代理對象。

那么 dubbo 在框架內(nèi)部是如何實(shí)現(xiàn)的呢?下面我們來具體分析一下它的源碼實(shí)現(xiàn)。

我們在 xml 里面配置 dubbo 服務(wù)的引用,其實(shí)是 dubbo 實(shí)現(xiàn)了自定義命名空間的方式來集成 Spring 框架。這樣通過 Spring 的 IOC 特性可以很方便的創(chuàng)建 dubbo 的配置對象。

這里寫圖片描述

對于 <reference: /> 標(biāo)簽 Spring 會把它解析成 ReferenceBean 對象,并且這個對象是一個 FactoryBean。所以當(dāng)我們通過 Spring 依賴注入這個對象的時候會調(diào)用 ReferenceBean#getObject 獲取接口對象的實(shí)例。它會把參數(shù)解析到一個 Map 中,然后根據(jù)其中的參數(shù)創(chuàng)建服務(wù)引用的代理對象。Map 里面的值大概如下所示:

這里寫圖片描述

1、ReferenceConfig#createProxy

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

2、Procotol#refer

和服務(wù)暴露一樣,consumer 端進(jìn)行服務(wù)調(diào)用的時候,可以對 dubbo 框架進(jìn)行擴(kuò)展:com.alibaba.dubbo.rpc.ExporterListenercom.alibaba.dubbo.rpc.Filter。所以獲取到的 Procotol 實(shí)例的結(jié)構(gòu)是:

  • ProtocolListenerWrapper
    • ProtocolFilterWrapper
      • RegistryProtocol

1、RegistryFactory#getRegistry獲取到 zookeeper 注冊中心,和服務(wù)暴露獲取注冊中心的邏輯一樣。
2、創(chuàng)建注冊服務(wù)目錄 RegistryDirectory
3、注冊服務(wù)消費(fèi)者 URL 到 zookeeper,其實(shí)就是創(chuàng)建 zookeeper 的節(jié)點(diǎn),和服務(wù)端發(fā)布類似。

/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 以下結(jié)點(diǎn),當(dāng)服務(wù)發(fā)生變更時,銷毀無效的 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、調(diào)用cluster#join(directory) 合并 invoker 創(chuàng)建并提供集群 failover (故障轉(zhuǎn)移)調(diào)用策略

  • 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對象、服務(wù)URL、ExchangeClient和Set<Invoker<?>> invokers創(chuàng)建 DubboInvoke 對象
2、獲取 ExchangeClient 數(shù)據(jù)交換客戶端 HeaderExchangeClient,并創(chuàng)建心跳連接。默認(rèn)是創(chuàng)建 Netty 客戶端用來調(diào)用暴露的遠(yuǎn)程調(diào)用。
3、將創(chuàng)建的 invoker (服務(wù)調(diào)用者)返回給目錄服務(wù),用來刷新 RegistryDirectory 中的Map<String, List<Invoker<T>>> methodInvokerMap對象。

4、ProxyFactory#getProxy

通過代理工廠創(chuàng)建服務(wù)引用接口的代理對象,用于訪問暴露的遠(yuǎn)程服務(wù)。

1、根據(jù) dubbo SPI 機(jī)制默認(rèn)獲取到 JavassistProxyFactory 對象
2、通過上面獲取到的 Invoke對象以及引用的遠(yuǎn)程服務(wù)接口 + dubbo 里面的 EchoService 調(diào)用AbstractProxyFactory#getProxy(Invoker<T>, Class<?>[])獲取到代理對象。
3、使用 JDK 里面的 InvocationHandler 對象代理遠(yuǎn)程暴露服務(wù) Invoke 調(diào)用對象創(chuàng)建遠(yuǎn)程暴露服務(wù)接口代理對象。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 流程圖 這個流程對應(yīng)我們這次源碼分析主要內(nèi)容,不得不說dubbo的文檔寫的太好了 時序圖 引用服務(wù)兩種方式 直連引...
    土豆肉絲蓋澆飯閱讀 649評論 0 1
  • 1:RPC協(xié)議擴(kuò)展,封裝遠(yuǎn)程調(diào)用細(xì)節(jié) 擴(kuò)展接口: com.alibaba.dubbo.rpc.Protocol c...
    漫步_2310閱讀 2,328評論 0 11
  • dubbo暴露服務(wù)有兩種情況,一種是設(shè)置了延遲暴露(比如delay="5000"),另外一種是沒有設(shè)置延遲暴露或者...
    加大裝益達(dá)閱讀 21,413評論 5 36
  • 注:文章中使用的dubbo源碼版本為2.5.4 零、文章目錄 一、服務(wù)引用的目的二、關(guān)鍵概念及關(guān)系三、服務(wù)引用流程...
    益文的圈閱讀 7,002評論 4 21
  • 文/狄佐 阿澤躺在硬邦邦的床上,輾轉(zhuǎn)反側(cè),翻來覆去,可依舊沒有絲毫睡意。他打開放在床頭柜上的手機(jī),看了一眼,上面顯...
    蒼淼閱讀 130,616評論 1 9

友情鏈接更多精彩內(nèi)容