一、基本概念
服务目录到底是什么?
服务目录也就是 Directory,其实之前也介绍过的,但不是单独拎出来讲的,可能大伙儿还不太清晰,今儿咱再来盘一下。
服务目录到底是个什么东西呢,看名字好像就是服务的目录,通过这个目录来查找远程服务?
对了一半!可以通过服务目录来查找远程服务,但是它不是"目录",实际上它是一堆 invoker 的集合,
前面说到服务的提供者都会集群部署,所有同样的服务会有多个提供者,因此就搞个服务目录来聚集它们,到时候要选择的时候就去服务目录里挑。
而服务提供者们也不是一成不变的,比如集群中加了一台服务提供者,那么相应的服务目录就需要添加一个 invoker,下线了一台服务提供者,目录里面也需要删除对应的 invoker,修改了配置也一样得更新。
所以这个服务目录其实还实现了监听注册中心的功能(指的是 RegistryDirectory )。
这个 Node 就不管了,主要是看 Directory ,正常操作搞一个抽象类来实现 Directory 接口,抽象类会实现一些公共方法,并且定义好逻辑,然后具体的实现由子类来完成,可以看到有两个子类,分别是 StaticDirectory 和 RegistryDirectory。
RegistryDirectory
我们先来看下 RegistryDirectory ,它是一个动态目录,我们来看一下具体的结构。
从截图可以看到 RegistryDirectory 内部存储了 DemoService 的两个服务提供者 url 和对应的 invoker。
而且从上面的继承结构也可以看出,它实现了 NotifyListener 接口,所以它可以监听注册中心的变化,当服务中心的配置发生变化之后, RegistryDirectory 就可以收到变更通知,然后根据配置刷新其 Invoker 列表。
所以说 RegistryDirectory 一共有三大作用:
获取 invoker 列表
监听注册中心的变化
刷新 invokers。
获取 invoker 列表,RegistryDirectory 实现的父类抽象方法 doList,其目的就是得到 invoker 列表,而其内部的实现主要是做了层方法名的过滤,通过方法名找到对应的 invokers。
@Override
public List<Invoker<T>> doList(Invocation invocation) {
if (forbidden) {
// 1. No service provider 2. Service providers are disabled
throw new RpcException(RpcException.FORBIDDEN_EXCEPTION, "No provider available from registry " +
getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " +
NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() +
", please check status of providers(disabled, not registered or in blacklist).");
}
if (multiGroup) {
return this.invokers == null ? Collections.emptyList() : this.invokers;
}
List<Invoker<T>> invokers = null;
try {
// Get invokers from cache, only runtime routers will be executed.
invokers = routerChain.route(getConsumerUrl(), invocation);
} catch (Throwable t) {
logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
}
return invokers == null ? Collections.emptyList() : invokers;
}
监听注册中心的变化,通过实现 NotifyListener 接口能感知到注册中心的数据变更,这其实是在服务引入的时候就订阅的。
public void subscribe(URL url) {
setConsumerUrl(url);
registry.subscribe(url, this); //订阅
}
RegistryDirectory 定义了三种集合,分别是 invokerUrls 、routerUrls 、configuratorUrls 分别处理相应的配置变化,然后对应转化成对象。
@Override
public synchronized void notify(List<URL> urls) {
Map<String, List<URL>> categoryUrls = urls.stream()
.filter(Objects::nonNull)
.filter(this::isValidCategory)
.filter(this::isNotCompatibleFor26x)
.collect(Collectors.groupingBy(url -> {
if (UrlUtils.isConfigurator(url)) {
return CONFIGURATORS_CATEGORY;
} else if (UrlUtils.isRoute(url)) {
return ROUTERS_CATEGORY;
} else if (UrlUtils.isProvider(url)) {
return PROVIDERS_CATEGORY;
}
return "";
}));
//通过url生成 configurator
List<URL> configuratorURLs = categoryUrls.getOrDefault(CONFIGURATORS_CATEGORY, Collections.emptyList());
this.configurators = Configurator.toConfigurators(configuratorURLs).orElse(this.configurators);
//通过url生成 router
List<URL> routerURLs = categoryUrls.getOrDefault(ROUTERS_CATEGORY, Collections.emptyList());
toRouters(routerURLs).ifPresent(this::addRouters);
//通过url生成 providers
List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());
//刷新或者覆盖invoker 根据注册中心监听的变化
//providerURLs: dubboo://ip:port
refreshOverrideAndInvoker(providerURLs);
}
刷