<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服務(wù)暴露

          共 5932字,需瀏覽 12分鐘

           ·

          2021-09-04 20:23




          前言


          上一篇呢,大家應(yīng)該都看過了吧,帶著大家把RPC、HTTP+Restful、Dubbo的來(lái)源、以及Dubbo的架構(gòu),簡(jiǎn)單的介紹了下Dubbo的服務(wù)暴露、引用和消費(fèi),以及DubboSPI機(jī)制

          當(dāng)然一些技術(shù)點(diǎn),只是蜻蜓點(diǎn)水,比如服務(wù)暴露,我們只說了個(gè)這玩意啥意思,代表著啥,很多仙子們可能還是處于懵逼狀態(tài),別急,你懵逼的點(diǎn)我都會(huì)一一詳細(xì)介紹,帶著大家撥開云霧見天明


          今天我們要分析的就是Dubbo的服務(wù)暴露過程,這個(gè)過程屬于Dubbo的核心過程之一了,因?yàn)?span style="font-family:Calibri;">Dubbo的大體流程就是服務(wù)暴露->服務(wù)引用->服務(wù)消費(fèi)這幾個(gè)主流程,當(dāng)然還會(huì)涉及到注冊(cè)發(fā)現(xiàn)、負(fù)載均衡、集群容錯(cuò)等,我們會(huì)從源碼的角度來(lái)給大家分析這個(gè)服務(wù)暴露的流程,當(dāng)然大家也不用發(fā)愁,我們不會(huì)把代碼分析的那么細(xì),咱也沒那個(gè)時(shí)間和精力,所以大家不用擔(dān)心讀不懂,我也會(huì)和大家說一下總結(jié)性話術(shù)來(lái)幫助大家去理解

          Dubbo的三種調(diào)用方式:

          1、注解@Reference調(diào)用(這是最常用的)
          @Reference(version = "1.0.0")private UserService userService;

          2、指定dubbo的服務(wù)端口進(jìn)行調(diào)用
          String url = "dubbo://192.168.1.102:10086/ccom.dayu.api.business.cache.IMerchantRedisCache?version=1.0.0";//更改不同的Dubbo服務(wù)暴露的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中獲取到服務(wù)提供者的信息,再進(jìn)行調(diào)用


          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í),我們中的大多數(shù)人對(duì) URL 這個(gè)概念并不會(huì)感到陌生。統(tǒng)一資源定位器 (Uniform Resource Locators)應(yīng)該是最廣為人知的一個(gè) RFC 規(guī)范,它的定義也非常簡(jiǎn)單,因特網(wǎng)上的可用資源可以用簡(jiǎn)單字符串來(lái)表示,該文檔就是描述了這種字符串的語(yǔ)法和語(yǔ)義,而這些字符串則被稱為:“統(tǒng)一資源定位器”(URL

          一個(gè)標(biāo)準(zhǔn)的 URL 格式至多可以包含如下的幾個(gè)部分
          protocol://username:password@host:port/path?key=value&key=value

          接下來(lái)我們看下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、thrifthttp、zk
            username/password:用戶名/密碼
            host/port:主機(jī)IP地址/端口號(hào)
            path:接口名稱
            parameter:參數(shù)鍵值對(duì)

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

          在沒有 URL 之前,只能以字符串傳遞參數(shù),不停的解析和拼裝,導(dǎo)致相同類型的接口,參數(shù)時(shí)而 Map, 時(shí)而 Parameters 類包裝:
          export(String url) createExporter(String host, int port, Parameters params)
          使用 URL一致性模型:
          export(URL url) createExporter(URL url)


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

          1.   編碼規(guī)范,使得代碼易寫,易讀
          2.   可擴(kuò)展性強(qiáng),URL 相當(dāng)于參數(shù)的集合(相當(dāng)于一個(gè) Map)
          3.   統(tǒng)一模型,各個(gè)擴(kuò)展模塊都可以使用它作為參數(shù)的表達(dá)形式


          服務(wù)暴露主流程



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

          客觀流程角度:
          前置工作,主要用于檢查參數(shù),組裝 URL。
          導(dǎo)出服務(wù),包含暴露服務(wù)到本地 (JVM),和暴露服務(wù)到遠(yuǎn)程兩個(gè)過程。
          向注冊(cè)中心注冊(cè)服務(wù),用于服務(wù)發(fā)現(xiàn)。

          對(duì)象轉(zhuǎn)換角度:
          首先將服務(wù)的實(shí)現(xiàn)封裝成一個(gè)Invoker,Invoker中封裝了服務(wù)的實(shí)現(xiàn)類。
          將Invoker封裝成Exporter,并緩存起來(lái),緩存里使用Invokerurl作為key。
          服務(wù)端Server啟動(dòng),監(jiān)聽端口。


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

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


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

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



          所以新繼承的ApplicationEventPublisherAware這個(gè)接口好像并沒有直接對(duì)服務(wù)暴露過程有作用。那么ServiceConfigexport的方法到底再哪里才會(huì)進(jìn)行調(diào)用呢?

          追根溯源發(fā)現(xiàn)DubboBootstrapApplicationListener這個(gè)類,繼承了ApplicationListenerApplicationContextAware,并最后調(diào)用到DubboBootStrap方法


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


          這個(gè)exportServices會(huì)最中調(diào)用ServiceConfigBaseexport方法,我們看下這個(gè)ServiceConfigBase是何方神圣呢

          打開ServiceConfig的結(jié)構(gòu)圖看下:


          原來(lái)如此,原來(lái)是父類,這是一個(gè)抽象方法,最終調(diào)用的就是ServiceConfig中的export方法了,我們重點(diǎn)要看的是export中的doExport方法



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

          我們點(diǎn)進(jìn)來(lái)doExportUrlsFor1Protocol這個(gè)方法看,這個(gè)方法很長(zhǎng),我們就不一步步的去看了,滑到方法最后這里:



          本地暴露和遠(yuǎn)程暴露


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

          本地暴露:調(diào)用的服務(wù)在同一臺(tái)JVM的時(shí)候會(huì)直接本地調(diào)用


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


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


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

          本地暴露存在的意義:因?yàn)榭赡艽嬖谕粋€(gè) JVM 內(nèi)部引用自身服務(wù)的情況,因此暴露的本地服務(wù)在內(nèi)部調(diào)用的時(shí)候可以直接消費(fèi)同一個(gè) JVM 的服務(wù)避免了網(wǎng)絡(luò)間的通信。

          一起來(lái)看一波exportLocal的時(shí)序圖:



          遠(yuǎn)程暴露:本機(jī)的服務(wù)暴露給別的機(jī)器的消費(fèi)者使用


          把目光聚焦到 DubboProtocol#export 方法和其內(nèi)部的openServer()方法上,可以看到這里的關(guān)鍵其實(shí)就是打開 Server ,RPC 肯定需要遠(yuǎn)程調(diào)用,這里我們用的是 NettyServer 來(lái)監(jiān)聽服務(wù)。

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



          總結(jié)

          好了,以上就是全部?jī)?nèi)容了,我是小魚仙,你們的學(xué)習(xí)成長(zhǎng)小伙伴         

                                                                    

          我希望有一天能夠靠寫字養(yǎng)活自己,現(xiàn)在還在磨練,這個(gè)時(shí)間可能會(huì)有很多年,感謝你們做我最初的讀者和傳播者。請(qǐng)大家相信,只要給我一份愛,我終究會(huì)還你們一頁(yè)情的。

          再次感謝大家能夠讀到這里,我后面會(huì)持續(xù)的更新技術(shù)文章以及一些記錄生活的靈魂文章,如果覺得不錯(cuò)的,覺得大魚同學(xué)有點(diǎn)東西的話,求點(diǎn)贊、關(guān)注、分享三連

          哦,對(duì)了!后續(xù)的更新文章我都會(huì)及時(shí)放到這里,歡迎大家點(diǎn)擊觀看,都是干貨文章啊,建議收藏,以后隨時(shí)翻閱查看

          https://github.com/DayuMM2021/Java

          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  麻豆精品三级 | 国产成人自拍网 | 色四虎 | 大香蕉色伊人 | 天天舔天天爱 |