Dubbo 服务暴露和引用总结
本文是对前面关于服务暴露和引用的总结与补充,完整 Dubbo 相关博客可在引用中查看
Dubbo 调用流程
-
Provider
- start 启动服务
- register 注册服务到服务中心
-
Consumer
-
subscribe 向注册中心订阅服务。只订阅使用到的服务,首次会拉取订阅的服务列表,缓存在本地
-
[异步] notify 当服务发生变化,获取最新的服务列表,更新本地缓存
-
-
invoke 调用
- Conusmer 直接发起对 Provider 的调用,无需注册中心。而对多个 Provider 的负载均衡,Consumer 通过 cluster 组件实现
-
count 监控
- [异步] Conusmer 和 Provider 都异步通知监控中心
服务暴露和服务引用
解析服务
- 基于
dubbo.jar
内的META-INF/spring.handles
配置,Spring 在遇到 dubbo 名称空间时,会回调 DubboNamespaceHandler - 所有的 dubbo 标签,都会统一用 DubboBeanDefinitionParser 进行解析,将 XML 标签解析成 Bean 对象
- 在 ServiceConfig#export() 或 ReferenceConfig#get() 初始化时,将 Bean 对象转换成 URL 格式,所有 Bean 属性转成 URL 参数
- 将 URL 传给 Dubbo SPI,基于 SPI 自适应机制,根据 URL 协议投,进行不同服务的暴露或引用。
服务暴露
官方文开发者指南 - 实现细节档给出服务提供者暴露一个服务的详细过程:
本地暴露
-
在没有注册中心,直接暴露提供者的情况下,ServiceConfig 解析出的 URL 格式为:
dubbo://service-host/{服务名}/{版本号}
-
基于 Dubbo SPI 的自适应机制,通过 URL
dubbo://
协议头识别,直接调用 DubboProtocol#export() 方法,打开服务端口-
根据解析出的 URL,创建一个新的 URL,将协议头设置为
injvm
,并设置主机名以及端口值 -
将具体的服务类名,比如
DubboServiceInjvmImpl
,通过 ProxyFactory 包装成 Invoker 实例 -
使用 InjvmProtocol 暴露 Invoker 实例并将其转化为 Exporter 实例
-
最后将生成的 Exporter 实例存放到 ServiceConfig 的
List<Exporter> exporters
中
-
远程暴露
- 在有注册中心,需要注册提供者地址的情况下,ServiceConfig 解析出的 URL 格式为:
registry:// registry-host/org.apache.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/{服务名}/{版本号}")
- 基于 Dubbo SPI 的自适应机制,通过 URL
registry://
协议头识别,就调用 RegistryProtocol#export() 方法- 将具体的服务类名,比如
DubboServiceRegistryImpl
,通过 ProxyFactory 包装成 Invoker 实例 - 调用 doLocalExport 方法,使用 DubboProtocol 将 Invoker 转化为 Exporter 实例,并打开 Netty 服务端监听客户请求
- 创建 Registry 实例,连接 Zookeeper,并在服务节点下写入提供者的 URL 地址,注册服务
- 向注册中心订阅 override 数据,并返回一个 Exporter 实例
- 将具体的服务类名,比如
- 根据 URL 格式中的
"dubbo://service-host/{服务名}/{版本号}"
中协议头dubbo://
识别,调用 DubboProtocol#export() 方法,开发服务端口 - RegistryProtocol#export() 返回的 Exporter 实例存放到 ServiceConfig 的
List<Exporter> exporters
中
服务引用
官方文开发者指南 - 实现细节档给出服务提供者暴露一个服务的详细过程:
本地引用
- 在没有注册中心,直连提供者的情况下,ReferenceConfig 解析出的 URL 格式为:
dubbo://service-host/com.foo.FooService?version=1.0.0
- 基于拓展点自适应机制,通过 URL 的
dubbo://
协议头识别,直接调用 DubboProtocol 的 refer 方法,直接生成 Invoker - Invoker 创建完毕后,调用 ProxyFactory 为服务接口生成代理对象,返回提供者引用
远程引用
- 从注册中心发现引用服务:在有注册中心,通过注册中心发现提供者地址的情况下,ReferenceConfig 解析出的 URL 格式为:
registry://registry-host:/org.apache.registry.RegistryService?refer=URL.encode("conumer-host/com.foo.FooService?version=1.0.0")
。 - 通过 URL 的
registry://
协议头识别,就会调用RegistryProtocol#refer()
方法- 查询提供者 URL,如
dubbo://service-host/com.foo.FooService?version=1.0.0
,来获取注册中心 - 创建一个 RegistryDirectory 实例并设置注册中心和协议
- 生成 conusmer 连接,在 consumer 目录下创建节点,向注册中心注册
- 注册完毕后,订阅 providers,configurators,routers 等节点的数据
- 通过 URL 的
dubbo://
协议头识别,调用DubboProtocol#refer()
方法,创建一个 ExchangeClient 客户端并返回 DubboInvoker 实例
- 查询提供者 URL,如
- 由于一个服务可能会部署在多台服务器上,这样就会在 providers 产生多个节点,这样也就会得到多个 DubboInvoker 实例,就需要 RegistryProtocol 调用 Cluster 将多个服务提供者节点伪装成一个节点,并返回一个 Invoker
- Invoker 创建完毕后,调用 ProxyFactory 为服务接口生成代理对象,返回提供者引用