天天看點

Dubbo服務暴露原了解析,帶你手撕源碼

文章目錄

      • 1.概述
      • 2.服務暴露源碼分析
        • ServiceConfig.export()
        • ServiceConfig.doExport()
        • ServiceConfig.doExportUrls()
        • ServiceConfig.doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List< URL > registryURLs)
        • RegistryProtocol.export(final Invoker< T > originInvoker)
        • DubboProtocol.export(Invoker< T > invoker)
        • DubboProtocol.openServer(URL url)
        • DubboProtocol.createServer(URL url)
        • NettyTransporter.bind(URL url, ChannelHandler handler)
        • NettyServer.doOpen()

1.概述

本文将一步一步的分析Dubbo服務暴露過程的源碼,探究其實作的過程,選擇的Dubbo版本是2.7.8。

測試代碼如下:

@Test
public void openService() throws IOException {
    // 服務配置
    ServiceConfig serviceConfig = new ServiceConfig();
    // 應用
    ApplicationConfig app = new ApplicationConfig("coderead-server");
    serviceConfig.setApplication(app);
    // 協定
    ProtocolConfig protocol = new ProtocolConfig("dubbo");
    protocol.setPort(8080);
    serviceConfig.setProtocol(protocol);
    // 注冊中心
    RegistryConfig registry = new RegistryConfig("zookeeper://127.0.0.1:2181");
    serviceConfig.setRegistry(registry);
    // 接口
    serviceConfig.setInterface(UserService.class);
    // 實作
    serviceConfig.setRef(new UserServiceImpl(8080));
    // 開啟服務
    serviceConfig.export();
    System.in.read();
}
           

測試代碼前面的部分就是設定服務的一些配置資訊

服務的暴露是通過serviceConfig.export()來完成的,下面将分析export的執行過程,看看它究竟做了哪些事情。

2.服務暴露源碼分析

ServiceConfig.export()

Dubbo服務暴露原了解析,帶你手撕源碼

初始化服務的一些元資訊,然後調用doExport()

ServiceConfig.doExport()

Dubbo服務暴露原了解析,帶你手撕源碼

判斷是否該服務已經暴露過,如果暴露過了則不再進行暴露,若沒有則會調用doExportUrls()。

ServiceConfig.doExportUrls()

Dubbo服務暴露原了解析,帶你手撕源碼

首先獲得服務注冊器,目前的服務注冊器中的内容如下:

Dubbo服務暴露原了解析,帶你手撕源碼

僅有兩個dubbo自帶的兩種服務,一個是心跳服務EchoService,另一個是GenericService,提供泛化接口,用來進行泛化調用。這兩個服務這裡暫時不做說明,本文的重點不在這裡。

執行完第二行代碼後,服務注冊器當中多了我們想要暴露的服務UserService,服務中有服務的描述,記錄了服務的名字、服務的接口類型,服務的方法等資訊。

Dubbo服務暴露原了解析,帶你手撕源碼

第三行代碼是往服務注冊器當中注冊服務提供者,執行之後repository如下,提供者記錄了服務的執行個體、中繼資料、服務配置資訊等。

Dubbo服務暴露原了解析,帶你手撕源碼

之後擷取用于注冊的url,此例子中隻有一個zookeeper注冊中心。

Dubbo服務暴露原了解析,帶你手撕源碼

for循環,周遊protocols協定,這裡也說明了dubbo支援多協定,可以将一個服務暴露不同協定的服務。

調用doExportUrlsFor1Protocol(protocolConfig, registryURLs)

ServiceConfig.doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List< URL > registryURLs)

該方法的邏輯很長,暫時不用去深究細節,僅僅關注服務暴露的部分。

Dubbo服務暴露原了解析,帶你手撕源碼

擷取該url中配置的scope,根據這個參數有兩種暴露可以選擇,一種是本地暴露,另一個是遠端暴露

本地暴露

Dubbo服務暴露原了解析,帶你手撕源碼
Dubbo服務暴露原了解析,帶你手撕源碼

建構一個InjvmExporter,不需要開啟netty服務,相當提供一個在本地可調用服務。

遠端暴露

Dubbo服務暴露原了解析,帶你手撕源碼

基于代理工廠将接口的實作類ref封裝成Invoker對象,然後調用Protocol的export方法,經過一系列的包裝類,調用RegistryProtocol中的export方法。

RegistryProtocol.export(final Invoker< T > originInvoker)

Dubbo服務暴露原了解析,帶你手撕源碼

doLocalExport真正執行開啟服務并暴露服務的方法。最終會調用到DubboProtocol中的export。

RegistryProtocol 此處的作用就是等服務開啟暴露完畢後,将服務的位址注冊到注冊中心當中。此例子中就是将服務的位址注冊到zookeeper。

DubboProtocol.export(Invoker< T > invoker)

Dubbo服務暴露原了解析,帶你手撕源碼

基于url擷取服務的key,也就是服務的全限定類名:端口号

将Invoker封裝成DubboExporter,儲存在exporterMap當中。

然後調用openServer(url)開啟服務。

DubboProtocol.openServer(URL url)

Dubbo服務暴露原了解析,帶你手撕源碼

serverMap當中還沒有目前的協定服務ProtocolServer,是以會調用createServer來建構一個協定服務。

DubboProtocol.createServer(URL url)

Dubbo服務暴露原了解析,帶你手撕源碼

協定url中設定一些參數,比如心跳服務的周期,預設1分鐘等。

擷取遠端路由服務,預設使用netty

調用Exchangers.bind 建構協定服務。

Dubbo服務暴露原了解析,帶你手撕源碼

參數校驗,然後擷取Exchanger調用bind

Dubbo服務暴露原了解析,帶你手撕源碼

調用Transporters.bind

Dubbo服務暴露原了解析,帶你手撕源碼

擷取Transporter,然後調用bind方法

NettyTransporter.bind(URL url, ChannelHandler handler)

最終來到NettyTransporter當中的bind

Dubbo服務暴露原了解析,帶你手撕源碼

基于url和ChannelHandler開啟netty服務。

Dubbo服務暴露原了解析,帶你手撕源碼

調用父類的構造方法

Dubbo服務暴露原了解析,帶你手撕源碼

屬性的設定,然後調用doOpen,實作真正開啟netty服務的方法。

NettyServer.doOpen()

Dubbo服務暴露原了解析,帶你手撕源碼

學過netty的應該比較熟悉這段代碼,初始化并開啟了一個netty服務,服務就這樣暴露出去了。

建構好的服務會儲存在DubboProtocol的serverMap當中

Dubbo服務暴露原了解析,帶你手撕源碼