Dubbo源码|十七、Dubbo服务暴露—注册Zookeeper

939 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第21天,点击查看活动详情

开篇

本文主要介绍Dubbo服务暴露过程——将服务URL注册到Zookeeper。

Dubbo服务暴露(一)

Dubbo服务暴露(二)

Dubbo服务暴露(三)

Dubbo服务暴露(四)

Dubbo服务暴露(五)

将服务URL注册到注册中心的入口是在RegistryProtocol#export方法中,首先是获取注册中心信息、要注册的URL,判断是否要进行注册,要注册的话,就将URL注册到注册中心。

final Registry registry = getRegistry(originInvoker);
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);

boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
    registry.register(registeredProviderUrl);
}

获取注册中心

image.png

  1. 从invoker对象中获取注册注册中心URL,URL示例如下: zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?xxxx
  2. 根据URL获取具体的注册中心实例。

通过DubboSPI以及URL获取RegistryFactory接口的实现对象,是根据URL的protocol参数来确定的,获取到的最终对象的类为ListenerRegistryWrapper。在这个类中,有个属性Registry,这个属性对应的类为ZookeeperRegistry,来看下是如何得到的。

public class RegistryFactoryWrapper implements RegistryFactory {
    private RegistryFactory registryFactory;

    public RegistryFactoryWrapper(RegistryFactory registryFactory) {
        this.registryFactory = registryFactory;
    }

    @Override
    public Registry getRegistry(URL url) {
        return new ListenerRegistryWrapper(registryFactory.getRegistry(url),
                Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(RegistryServiceListener.class)
                        .getActivateExtension(url, "registry.listeners")));
    }
}

在最后return的时候,初始化了ListenerRegistryWrapper,这个ListenerRegistryWrapper构造函数第一个参数就是Registry。那么registryFactory是如何得到的呢?

还记得之前介绍过Dubbo依赖注入吗?这个是通过依赖注入进来的,取得值根据URL的protocol参数来确定的,所以这个registryFactory对应的类为:ZookeeperRegistryFactory

getRegistry

image.png

这个方法主要是获取注册中心对象:

  1. 判断是否销毁
  2. 构造URL添加、删除一些参数,最终格式如下: zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=xxxxx
  3. 判断缓存里是否存在已经创建的注册中心实例,如果有直接返回。
  4. 如果没有则进行创建注册中心实例,并放入缓存。
  5. 创建实例也很简单直接new一个ZookeeperRegistry并返回。

创建ZookeeperRegistry

image.png

  1. 首先调用父类构造方法,加载一些配置,创建缓存文件。
  2. 获取URL的group参数,默认为dubbo
  3. 在group前面加上根路径,作为Zookeeper的根节点。
  4. 添加Zookeeper状态监听,如果失败的话会进行重连。

注册

调用registry.register(registeredProviderUrl)方法进行URL的注册。 该方法是在ZookeeperRegistry的父类FailbackRegistry里。

image.png 该方法主要处理过程如下:

  1. 根据URLaccepts参数,判断是否与注册中心匹配。
  2. 将URL添加到已注册列表。
  3. 将URL从未注册、注册失败列表中移除。
  4. 调用doRegister方法进行注册,在该方法中调用zkClient.create将URL注册到注册中心。
  5. 如果注册失败,将URL方法注册失败列表,然后进行重试。
public void doRegister(URL url) {
    try {
        zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true));
    } catch (Throwable e) {
        throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

生成ZK路径

private String toUrlPath(URL url) {
    return toCategoryPath(url) + PATH_SEPARATOR + URL.encode(url.toFullString());
}
private String toCategoryPath(URL url) {
    return toServicePath(url) + PATH_SEPARATOR + url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
}

private String toServicePath(URL url) {
    String name = url.getServiceInterface();
    if (ANY_VALUE.equals(name)) {
        return toRootPath();
    }
    return toRootDir() + URL.encode(name);
}
private String toRootDir() {
    if (root.equals(PATH_SEPARATOR)) {
        return root;
    }
    return root + PATH_SEPARATOR;
}

toRootDir为获取根节点的值,这里为/dubbo/

toServicePath将接口类名加入路径,例如:/dubbo/org.apache.dubbo.demo.DemoService

toCategoryPath将URL类型参数加入路径,类型有providersconsumersconfigurators等,例如:/dubbo/org.apache.dubbo.demo.DemoService/providers

toUrlPath就是最终完整的注册路径了,例如:/dubbo/org.apache.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F192.168.43.94%3A20880%2Forg.apache.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddubbo-demo-annotation-provider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.demo.DemoService%26methods%3DsayHello%2CsayHelloAsync%26pid%3D54338%26release%3D%26service.name%3DServiceBean%3A%2Forg.apache.dubbo.demo.DemoService%26side%3Dprovider%26timestamp%3D1671032911346

后记

将服务URL注册到注册中心整体流程就是这些了,下篇计划介绍Dubbo服务的监听。