Dubbo源码|二十二、Dubbo服务引入——服务发现
开篇
本文介绍Dubbo服务引入部分的源码分析——服务发现。
服务发现
Dubbo的服务发现是在RegistryProtocol#refer方法中完成的,关于这个方法的工作流程上一篇已经介绍过了,这里不再赘述,本篇从RegistryProtocol#interceptInvoker方法开始。
protected <T> Invoker<T> interceptInvoker(ClusterInvoker<T> invoker, URL url, URL consumerUrl) {
List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);
if (CollectionUtils.isEmpty(listeners)) {
return invoker;
}
for (RegistryProtocolListener listener : listeners) {
listener.onRefer(this, invoker, consumerUrl);
}
return invoker;
}
该方法首先通过Dubbo SPI获取RegistryProtocolListener接口的实现类,然后遍历其所有的实现类,调用实现类的onRefer方法。RegistryProtocolListener接口的实现类为MigrationRuleListener。在onRefer方法中,处理逻辑也很简单调用MigrationRuleHandler#doMigrate方法。
doMigrate方法为迁移规则执行的,该方法有个参数rawRule,这个参数封装了迁移的配置规则的信息,默认人INIT,这个配置信息会被解析为MigrationRule类型。根据MigrationRule实例的信息,会调用MigrationInvoker#refreshInterfaceInvoker方法。
刷新接口级服务发现Invoker
public synchronized void refreshInterfaceInvoker() {
clearListener(invoker);
if (needRefresh(invoker)) {
invoker = registryProtocol.getInvoker(cluster, registry, type, url);
if (migrationMultiRegistry) {
setListener(serviceDiscoveryInvoker, () -> {
this.setAddressChanged();
});
}
}
}
该方法处理逻辑如下:
- 清空
invoker中的服务变更监听器,该监听器是存储在服务目录中的。 - 判断
invoker对象是否为空或者是否被销毁,如果是的话就需要刷新。 - 调用
getInvoker方法重新获得invoker。 - 设置服务监听。
获取invoker
调用registryProtocol.getInvoker方法重新获取invoker,还记得registryProtocol这个对象对应的是什么类吗?对应的是InterfaceCompatibleRegistryProtocol,这个类是通过DubboSPI加载进来的。
registry=org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol
service-discovery-registry=org.apache.dubbo.registry.integration.RegistryProtocol
继续看getInvoker方法,该方法会先初始化一个动态服务目录DynamicDirectory,然后调用doCreateInvoker方法来创建invoker对象。
public <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
DynamicDirectory<T> directory = new RegistryDirectory<>(type, url);
return doCreateInvoker(directory, cluster, registry, type);
}
创建invoker
protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
directory.setRegistry(registry);
directory.setProtocol(protocol);
Map<String, String> parameters = new HashMap<String, String>(directory.getConsumerUrl().getParameters());
URL urlToRegistry = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
if (directory.isShouldRegister()) {
directory.setRegisteredConsumerUrl(urlToRegistry);
registry.register(directory.getRegisteredConsumerUrl());
}
directory.buildRouterChain(urlToRegistry);
directory.subscribe(toSubscribeUrl(urlToRegistry));
return (ClusterInvoker<T>) cluster.join(directory);
}
该方法的工作流程如下:
- 将注册中心、协议等信息保存到服务目录。
- 从服务目录里获取服务url对应的参数,并去除无用的参数,例如
register.ip。 - 生成要注册的
url,此时协议为consumer。 - 判断是否需要注册,如果服务接口不为
*并且register值为true,就需要注册。 - 将消费者
url注册到注册中心。 - 根据注册
url构造路由链。 - 根据注册
url订阅服务。 - 生成
invoker并返回。
构造路由链
public void buildRouterChain(URL url) {
this.setRouterChain(RouterChain.buildChain(url));
}
public static <T> RouterChain<T> buildChain(URL url) {
return new RouterChain<>(url);
}
private RouterChain(URL url) {
List<RouterFactory> extensionFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class)
.getActivateExtension(url, ROUTER_KEY);
List<Router> routers = extensionFactories.stream()
.map(factory -> factory.getRouter(url))
.collect(Collectors.toList());
initWithRouters(routers);
}
路由就是我们可以设置一些规则,像网关一样,设置哪些服务提供者可以被哪些消费者调用,也可以对服务的调用进行限制等。
- 通过
DubboSPI机制获取RouterFactory接口的实现类,其实现类主要有四个:MockRouterFactory、TagRouterFactory、AppRouterFactory、ServiceRouterFactory。 - 遍历
RouterFactory实现类,调用getRouter方法创建Router实例; - 对
routers进行排序。
应用路由
AppRouter是在AppRouterFactory类中创建出来的,主要是监听应用级别的配置,例如:dubbo-demo-annotation-consumer.condition-router。
服务路由
ServiceRouter是在ServiceRouterFactory类中创建出来的,主要是监听服务级别的配置,路由key的格式格式为:{interfaceName}:[version]:[group],例如:org.apache.dubbo.demo.DemoService:1.0.0:test.condition-router。
标签路由
TagRouter是在TagRouterFactory类中创建出来的,主要是监听服务端的配置,例如:dubbo-demo-annotation-provider.tag-router。
dubbo-admin中可以对这些路由进行配置,通过这些配置可以达到服务分流、分组或者其他个性化的定制操作。
后记
下一篇将介绍Dubbo服务引入的服务目录的监听配置,对服务监听做详细介绍。
转载自:https://juejin.cn/post/7182429610423320632