开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第21天,点击查看活动详情
开篇
本文主要介绍Dubbo服务暴露过程——将服务URL注册到Zookeeper。
将服务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);
}
获取注册中心
- 从invoker对象中获取注册注册中心URL,URL示例如下:
zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?xxxx - 根据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
这个方法主要是获取注册中心对象:
- 判断是否销毁
- 构造URL添加、删除一些参数,最终格式如下:
zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=xxxxx - 判断缓存里是否存在已经创建的注册中心实例,如果有直接返回。
- 如果没有则进行创建注册中心实例,并放入缓存。
- 创建实例也很简单直接new一个
ZookeeperRegistry并返回。
创建ZookeeperRegistry
- 首先调用父类构造方法,加载一些配置,创建缓存文件。
- 获取URL的
group参数,默认为dubbo。 - 在group前面加上根路径,作为
Zookeeper的根节点。 - 添加
Zookeeper状态监听,如果失败的话会进行重连。
注册
调用registry.register(registeredProviderUrl)方法进行URL的注册。
该方法是在ZookeeperRegistry的父类FailbackRegistry里。
该方法主要处理过程如下:
- 根据
URL的accepts参数,判断是否与注册中心匹配。 - 将URL添加到已注册列表。
- 将URL从未注册、注册失败列表中移除。
- 调用doRegister方法进行注册,在该方法中调用
zkClient.create将URL注册到注册中心。 - 如果注册失败,将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类型参数加入路径,类型有providers、consumers、configurators等,例如:/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服务的监听。