Dubbo源码|二十二、Dubbo服务引入——服务发现
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第33天,点击查看活动详情
开篇
本文介绍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




