Directory代表多个invoker,其内部维护了一个list,并且这个list的内容时动态变化的(对于消费端来说,每个invoker代表一个服务提供者)。
在Dubbo中,RegistryDirectory和StaticDirectory都是Directory的实现类。
RegistryDirectory是一个动态服务目录,可以感知注册中心配置的变化,其持有的Invoker列表会随着注册中心内容的变化而变化。每次变化后,RegistryDirectory都会动态地增删Invoker,并调用Router的route方法进行路由,过滤掉不符合路由规则的Invoker。相反,StaticDirectory是一个静态服务目录,它内部存放的Invoker是不会变动的。
RegistryDirectory是Dubbo中默认使用的Directory,适用于服务提供者和消费者都动态变化的情况。而StaticDirectory适用于服务提供者和消费者相对固定,不需要频繁变动的场景。
RegistryDirectory是在服务消费端启动时创建的。
消费端启动时,通过 ReferenceConfig#get() 创建对服务提供方的远程调用代理类。最终在通过RegistryProtocol#refer() 创建invoker时创建了RegistryDirectory。具体实现细节如下所示。
public T get(boolean check) {
// ...
return ref;
}
protected synchronized void init(boolean check) {
// ...
// 创建对服务提供方的远程调用代理类
ref = createProxy(referenceParameters);
// ...
}
private T createProxy(Map referenceParameters) {
// ...
// 创建invoker
createInvoker();
// ...
// create service proxy
return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic));
}
private void createInvoker() {
if (urls.size() == 1) {
URL curUrl = urls.get(0);
invoker = protocolSPI.refer(interfaceClass, curUrl);
// ...
} else {
List> invokers = new ArrayList<>();
URL registryUrl = null;
for (URL url : urls) {
invokers.add(protocolSPI.refer(interfaceClass, url));
if (UrlUtils.isRegistry(url)) {
// use last registry url
registryUrl = url;
}
}
// ...
}
}
创建invoker的核心方法为
invoker = protocolSPI.refer(interfaceClass, curUrl);
服务注册和发现使用是register协议,因此上述方法实际上将调用 RegistryProtocol#refer方法,实现如下所示。
public Invoker refer(Class type, URL url) throws RpcException {
url = getRegistryUrl(url);
Registry registry = getRegistry(url);
if (RegistryService.class.equals(type)) {
return proxyFactory.getInvoker((T) registry, type, url);
}
// group="a,b" or group="*"
Map qs = (Map) url.getAttribute(REFER_KEY);
String group = qs.get(GROUP_KEY);
if (StringUtils.isNotEmpty(group)) {
if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
return doRefer(Cluster.getCluster(url.getScopeModel(), MergeableCluster.NAME), registry, type, url, qs);
}
}
Cluster cluster = Cluster.getCluster(url.getScopeModel(), qs.get(CLUSTER_KEY));
// 创建invoker
return doRefer(cluster, registry, type, url, qs);
}
protected Invoker doRefer(Cluster cluster, Registry registry, Class type, URL url, Map parameters) {
// ...
// 创建invoker
ClusterInvoker migrationInvoker = getMigrationInvoker(this, cluster, registry, type, url, consumerUrl);
return interceptInvoker(migrationInvoker, url, consumerUrl);
}
最终将调用下述方法创建RegistryDirectory。
public ClusterInvoker getInvoker(Cluster cluster, Registry registry, Class type, URL url) {
DynamicDirectory directory = new RegistryDirectory<>(type, url);
return doCreateInvoker(directory, cluster, registry, type);
}