文章目录
-
-
- 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当中