文章目錄
-
-
- 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()
初始化服務的一些元資訊,然後調用doExport()
ServiceConfig.doExport()
判斷是否該服務已經暴露過,如果暴露過了則不再進行暴露,若沒有則會調用doExportUrls()。
ServiceConfig.doExportUrls()
首先獲得服務注冊器,目前的服務注冊器中的内容如下:
僅有兩個dubbo自帶的兩種服務,一個是心跳服務EchoService,另一個是GenericService,提供泛化接口,用來進行泛化調用。這兩個服務這裡暫時不做說明,本文的重點不在這裡。
執行完第二行代碼後,服務注冊器當中多了我們想要暴露的服務UserService,服務中有服務的描述,記錄了服務的名字、服務的接口類型,服務的方法等資訊。
第三行代碼是往服務注冊器當中注冊服務提供者,執行之後repository如下,提供者記錄了服務的執行個體、中繼資料、服務配置資訊等。
之後擷取用于注冊的url,此例子中隻有一個zookeeper注冊中心。
for循環,周遊protocols協定,這裡也說明了dubbo支援多協定,可以将一個服務暴露不同協定的服務。
調用doExportUrlsFor1Protocol(protocolConfig, registryURLs)
ServiceConfig.doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List< URL > registryURLs)
該方法的邏輯很長,暫時不用去深究細節,僅僅關注服務暴露的部分。
擷取該url中配置的scope,根據這個參數有兩種暴露可以選擇,一種是本地暴露,另一個是遠端暴露
本地暴露
建構一個InjvmExporter,不需要開啟netty服務,相當提供一個在本地可調用服務。
遠端暴露
基于代理工廠将接口的實作類ref封裝成Invoker對象,然後調用Protocol的export方法,經過一系列的包裝類,調用RegistryProtocol中的export方法。
RegistryProtocol.export(final Invoker< T > originInvoker)
doLocalExport真正執行開啟服務并暴露服務的方法。最終會調用到DubboProtocol中的export。
RegistryProtocol 此處的作用就是等服務開啟暴露完畢後,将服務的位址注冊到注冊中心當中。此例子中就是将服務的位址注冊到zookeeper。
DubboProtocol.export(Invoker< T > invoker)
基于url擷取服務的key,也就是服務的全限定類名:端口号
将Invoker封裝成DubboExporter,儲存在exporterMap當中。
然後調用openServer(url)開啟服務。
DubboProtocol.openServer(URL url)
serverMap當中還沒有目前的協定服務ProtocolServer,是以會調用createServer來建構一個協定服務。
DubboProtocol.createServer(URL url)
協定url中設定一些參數,比如心跳服務的周期,預設1分鐘等。
擷取遠端路由服務,預設使用netty
調用Exchangers.bind 建構協定服務。
參數校驗,然後擷取Exchanger調用bind
調用Transporters.bind
擷取Transporter,然後調用bind方法
NettyTransporter.bind(URL url, ChannelHandler handler)
最終來到NettyTransporter當中的bind
基于url和ChannelHandler開啟netty服務。
調用父類的構造方法
屬性的設定,然後調用doOpen,實作真正開啟netty服務的方法。
NettyServer.doOpen()
學過netty的應該比較熟悉這段代碼,初始化并開啟了一個netty服務,服務就這樣暴露出去了。
建構好的服務會儲存在DubboProtocol的serverMap當中