<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官問我:解釋一下Dubbo服務暴露

          共 5197字,需瀏覽 11分鐘

           ·

          2021-09-13 16:37


          今天我們要分析的就是Dubbo的服務暴露過程,這個過程屬于Dubbo的核心過程之一了,因為Dubbo的大體流程就是服務暴露->服務引用->服務消費這幾個主流程,當然還會涉及到注冊發(fā)現(xiàn)、負載均衡、集群容錯等,我們會從源碼的角度來給大家分析這個服務暴露的流程,當然大家也不用發(fā)愁,我們不會把代碼分析的那么細,咱也沒那個時間和精力,所以大家不用擔心讀不懂,我也會和大家說一下總結性話術來幫助大家去理解


          Dubbo的三種調用方式:


          1、注解@Reference調用(這是最常用的)

          @Reference(version = "1.0.0")private UserService userService;

          2、指定dubbo的服務端口進行調用

          String url = "dubbo://192.168.1.102:10086/ccom.dayu.api.business.cache.IMerchantRedisCache?version=1.0.0";//更改不同的Dubbo服務暴露的ip地址&端口                  ReferenceBean<IMerchantRedisCache> referenceBean = new ReferenceBean<IMerchantRedisCache>();          referenceBean.setApplicationContext(applicationContext);          referenceBean.setInterface(IMerchantRedisCache.class);          referenceBean.setUrl(url);  
          try { referenceBean.afterPropertiesSet(); IMerchantRedisCache merchantRedisCache = referenceBean.get(); PlaneResDto<MerchantItem> resDto = merchantRedisCache.getInDubbo(419248146L); JsonPrinter.printJson(resDto); Assert.assertTrue(SysCode.SUCCESS.equals(resDto.getRspCd())); } catch (Exception e) { e.printStackTrace(); }

          3、從Zookeeper中獲取到服務提供者的信息,再進行調用


          ZkClient zkClient = new ZkClient(ZKServers,10000,10000,new SerializableSerializer()); List<String> lists = zkClient.getChildren("/dubbo/com.yc.api.business.cache.ICacheFacade/providers");




          URL

          URL統(tǒng)一模型的意義


          在不談及 dubbo 時,我們中的大多數(shù)人對 URL 這個概念并不會感到陌生。統(tǒng)一資源定位器 (Uniform Resource Locators)應該是最廣為人知的一個 RFC 規(guī)范,它的定義也非常簡單,因特網上的可用資源可以用簡單字符串來表示,該文檔就是描述了這種字符串的語法和語義,而這些字符串則被稱為:“統(tǒng)一資源定位器”(URL)


          一個標準的 URL 格式至多可以包含如下的幾個部分

          protocol://username:password@host:port/path?key=value&key=value

          接下來我們看下Dubbo中的URL:

          public URL(String protocol,               String username,               String password,               String host,               int port,               String path,               Map<String, String> parameters) {        if (StringUtils.isEmpty(username)                && StringUtils.isNotEmpty(password)) {            throw new IllegalArgumentException("Invalid url, password without username!");        }
          this.urlAddress = new PathURLAddress(protocol, username, password, path, host, port); this.urlParam = URLParam.parse(parameters); }

            protocol:一般是 dubbo 中的各種協(xié)議 如:dubbo、thrift、http、zk

            username/password:用戶名/密碼

            host/port:主機IP地址/端口號

            path:接口名稱

            parameter:參數(shù)鍵值對


          對于 dubbo 中的 URL,有人理解為配置總線,有人理解為統(tǒng)一配置模型,說法雖然不同,但都是在表達一個意思,這樣的 URL 在 dubbo 中被當做是公共契約,所有擴展點參數(shù)都包含 URL 參數(shù),URL 作為上下文信息貫穿整個擴展點設計體系。


          在沒有 URL 之前,只能以字符串傳遞參數(shù),不停的解析和拼裝,導致相同類型的接口,參數(shù)時而 Map, 時而 Parameters 類包裝:

          export(String url) createExporter(String host, int port, Parameters params)

          使用 URL一致性模型:

          export(URL url) createExporter(URL url)

          在最新的 dubbo 代碼中,我們可以看到大量使用 URL 來進行上下文之間信息的傳遞,這樣的好處是顯而易見的:


          1.   編碼規(guī)范,使得代碼易寫,易讀

          2.   可擴展性強,URL 相當于參數(shù)的集合(相當于一個 Map)

          3.   統(tǒng)一模型,各個擴展模塊都可以使用它作為參數(shù)的表達形式



          服務暴露主流程


          服務暴露主流程,大致可以分為兩個角度進行分析流程,大家先簡單理解下,下面我?guī)Т蠹乙徊讲降目丛创a:


          客觀流程角度:

          前置工作,主要用于檢查參數(shù),組裝 URL。

          導出服務,包含暴露服務到本地 (JVM),和暴露服務到遠程兩個過程。

          向注冊中心注冊服務,用于服務發(fā)現(xiàn)。


          對象轉換角度:

          首先將服務的實現(xiàn)封裝成一個Invoker,Invoker中封裝了服務的實現(xiàn)類。

          將Invoker封裝成Exporter,并緩存起來,緩存里使用Invoker的url作為key。

          服務端Server啟動,監(jiān)聽端口。



          初始化,這屬于入口,我們來看下其中的ServiceBean這個類的使用,這里說一個小插曲,經過對比發(fā)現(xiàn)最新的繼承的是ApplicationEventPublisherAware接口,而舊版本的繼承的是ApplicationListener<ContextRefreshedEvent>接口


          哦對了,源碼地址在:https://gitee.com/dayumm



          大部分博客視頻講解服務暴露的export方法根源是ServiceConfig的export方法,ServiceBean繼承了ServiceConfig,利用實現(xiàn)ApplicationListener<ContextRefreshedEvent>接口的onApplicationEvent方法最終調用ServiceConfig的export方法


          然而最新版本實現(xiàn)的ApplicationEventPublisherAware并沒有去調用ServiceConfig的export方法,只是ServiceBean在完成export的時候利用這個接口去發(fā)布一個exported的事件,也就是暴露后的事件,并不是暴露事件



          所以新繼承的ApplicationEventPublisherAware這個接口好像并沒有直接對服務暴露過程有作用。那么ServiceConfig的export的方法到底再哪里才會進行調用呢?


          追根溯源發(fā)現(xiàn)DubboBootstrapApplicationListener這個類,繼承了ApplicationListener和ApplicationContextAware,并最后調用到DubboBootStrap方法



          發(fā)現(xiàn)它再start方法中有一行exportServices,顧名思義是導出服務或者暴露服務,點進去看exportServices



          這個exportServices會最中調用ServiceConfigBase的export方法,我們看下這個ServiceConfigBase是何方神圣呢


          打開ServiceConfig的結構圖看下:



          原來如此,原來是父類,這是一個抽象方法,最終調用的就是ServiceConfig中的export方法了,我們重點要看的是export中的doExport方法



          可以看到 Dubbo 支持多注冊中心,并且支持多個協(xié)議,一個服務如果有多個協(xié)議那么就都需要暴露,比如同時支持 dubbo 協(xié)議和 hessian 協(xié)議,那么需要將這個服務用兩種協(xié)議分別向多個注冊中心(如果有多個的話)暴露注冊。


          我們點進來doExportUrlsFor1Protocol這個方法看,這個方法很長,我們就不一步步的去看了,滑到方法最后這里:




          本地暴露和遠程暴露


          繼續(xù)看源碼,快結束了,沖

          本地暴露:調用的服務在同一臺JVM的時候會直接本地調用


          Protocol 的 export 方法是標注了 @ Adaptive 注解的,因此會生成代理類,然后代理類會根據(jù) Invoker 里面的 URL 參數(shù)得知具體的協(xié)議,然后通過 Dubbo SPI 機制選擇對應的實現(xiàn)類進行 export,而這個方法就會調用 InjvmProtocol#export 方法


          InjvmProtocol:實際上就是具體實現(xiàn)類層層封裝, invoker 其實是由 Javassist 創(chuàng)建的,具體創(chuàng)建過程 proxyFactory.getInvoker 就不做分析了,對 Javassist 有興趣的同學自行去了解,之后可能會寫一篇,至于 dubbo 為什么用 javassist 而不用 jdk 動態(tài)代理是因為 javassist 快


          為什么封裝成invoker:至于為什么要封裝成 invoker 其實就是想屏蔽調用的細節(jié),統(tǒng)一暴露出一個可執(zhí)行體,這樣調用者簡單的使用它,向它發(fā)起 invoke 調用,它有可能是一個本地的實現(xiàn),也可能是一個遠程的實現(xiàn),也可能一個集群實現(xiàn)

          本地暴露存在的意義:因為可能存在同一個 JVM 內部引用自身服務的情況,因此暴露的本地服務在內部調用的時候可以直接消費同一個 JVM 的服務避免了網絡間的通信。

          一起來看一波exportLocal的時序圖:


          遠程暴露:本機的服務暴露給別的機器的消費者使用


          把目光聚焦到 DubboProtocol#export 方法和其內部的openServer()方法上,可以看到這里的關鍵其實就是打開 Server ,RPC 肯定需要遠程調用,這里我們用的是 NettyServer 來監(jiān)聽服務。

          再往更細的地方我就不一一分析了,大家感興趣的拉代碼去看吧,看懂大致流程和其中的設計思想最為關鍵

          有道無術,術可成;有術無道,止于術

          歡迎大家關注Java之道公眾號


          好文章,我在看??

          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  超污视频网站在线观看免费 | www.操屄 | 成人AV麻豆 | 九九成人网站 | 永久免费看黄网址 |