上篇文章如果有人问你 Dubbo 中注册中心工作原理,就把这篇文章给他大致了解了注册中心作用以及 Dubbo Registry 模块源码,这篇文章将深入 Dubbo ZooKeeper 模块,去了解如何实现服务动态的发现。
ps: 以下将 ZooKeeper 缩写为 zk。
一、dubbo zk 数据结构
在 ZooKeeper 基本概念分享一文讲道,ZK 内部是一种树形层次结构,节点存在多种类型。而 Dubbo 只会创建持久节点和临时节点。
若服务提供者服务接口为 com.service.FooService
,将会在 ZK 中创建创建如下路径 /dubbo/com.service.FooService/providers/providerURL
。
服务路径分为四层,根节点默认为 dubbo,可以在 dubbo-registry 设置 group 属性改变该值。
ps: 若无注册中心隔离需求,不要随便修改。
第二层节点为服务节点全名称,如 com.service.FooService
。
第三层节点为服务目录,如 providers。另外还存在其他目录节点,分别为 consumers(消费者目录),configurators(配置目录),routers(路由目录)。下面服务订阅主要针对这一层节点。
第四个节点为具体服务节点,节点名为具体的 URL 字符串,如 dubbo://2.0.1.13:12345/com.dubbo.example.DemoService?xx=xx
,该节点默认为临时节点。
dubbo ZK 树形内部结构示例为:
ZK 内部服务具体示例如下:
二、RegistryFactory 实现
Dubbo 可以在配置文件中指定使用注册中心,可以使用 dubbo.registry.protocol
指定具体注册中心类型,也可以设置 dubbo.registry.address
指定。注册中心相关实现将会使用 RegistryFactory
工厂类创建。
RegistryFactory
接口源码如下:
@SPI("dubbo")
public interface RegistryFactory {
@Adaptive({
"protocol"})
Registry getRegistry(URL url);
}
RegistryFactory
接口方法使用 @Adaptive
注解,这里将会使用 Dubbo SPI 机制,自动生成代码的一些实现逻辑。这里将会根据 URL 中 protocol
属性,去调用最终实现子类。
RegistryFactory
实现子类如图所示:
AbstractRegistryFactory
将会实现接口的 getRegistry
方法,主要完成加锁,并调用抽象模板方法 createRegistry
创建具体注册中心实现类,并将其缓存在内存中。
AbstractRegistryFactory#getRegistry
源码如下所示:
public Registry getRegistry(URL url) {
url = URLBuilder.from(url)
.setPath(RegistryService.class.getName())
.addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
.removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY)
.build();
String key = url.toServiceStringWithoutResolving();
// 加锁,防止并发
LOCK.lock();
try {
// 先从缓存中取
Registry registry = REGISTRIES.get(key);
if (registry != null) {
return registry;
}
//使用 Dubbo SPI 进制创建
registry = createRegistry(url);
if (registry