likes
comments
collection
share

Dubbo源码|二十三、Dubbo服务引入——服务监听

作者站长头像
站长
· 阅读数 13

前言

本文主要介绍Dubbo服务引入——服务监听部分,服务监听是监听服务的变动,比如提供者服务变动(新增、移除等)以及服务路由、动态配置的变动等。

正文

服务监听的代码位于RegistryProtocol#doCreateInvoker方法中。

protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
    directory.setRegistry(registry);
    // ... 删除部分代码
    directory.buildRouterChain(urlToRegistry);
    directory.subscribe(toSubscribeUrl(urlToRegistry));
    return (ClusterInvoker<T>) cluster.join(directory);
}

在该方法中有两处监听的设置,分别为buildRouterChainsubscribe

buildRouterChain

从上一篇我们了解到在构造路由链时,会初始化4个类,分别为:MockRouterFactory、 TagRouterFactoryAppRouterFactoryServiceRouterFactory,这几个工厂类中产生的实例对象中就有服务监听的处理逻辑。

buildRouterChain方法主要作用为构造路由链,路由链是动态服务目录中的一个属性,通过路由链可以过滤某些服务提供者,路由链会在引入服务时按路由条件进行过滤。

buildRouterChain方法里也会监听路由配置,因为新老版本路由配置存放的位置不一样,老版本是放在/dubbo/服务路径/routers里,而新版本则放在/dubbo/config/dubbo/服务路径里的。

例如,新版本监听路径:

/dubbo/config/dubbo/dubbo-demo-provider-application.tag-router和/dubbo/config/dubbo/org.apache.dubbo.demo.DemoService::.configurators

在构造路由链的过程中,会调用RouterChain的构造方法,通过factory工厂根据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);
}

Dubbo源码|二十三、Dubbo服务引入——服务监听

RouterFactory也是通过SPI机制,来获取到不同的路由器工厂,从而创建不同的路由。

在创建路由的过程中,会调用父类——ListenableRouterinit方法,来配置监听并获取配置的规则,拿到这些规则后,调用process方法进行处理,将路由规则rule解析成对应的路由规则类。

Dubbo源码|二十三、Dubbo服务引入——服务监听

subscribe

subscribe方法就是服务监听,为了兼容老版本,监听的目录有:

  • 服务的消费应用目录:/dubbo/config/dubbo/dubbo-demo-consumer-application.configurators
  • 服务的动态配置目录:/dubbo/config/dubbo/org.apache.dubbo.demo.DemoService:version:group.configurators
  • 服务的提供者目录:/dubbo/org.apache.dubbo.demo.DemoService/providers
  • 服务的动态配置目录(老版本):/dubbo/org.apache.dubbo.demo.DemoService/configurators
  • 服务的路由器目录(老版本):/dubbo/org.apache.dubbo.demo.DemoService/routers

toSubscribeUrl方法为urlToRegistry添加了一个key——category,这个key对应的三个参数分别为:providersconfiguratorsrouters,这三个参数代表着要监听的目录。

来看一下subscribe的具体实现:

  1. 将url记录到服务目录的consumerUrl属性中
  2. 监听consumer应用,即/dubbo/config/dubbo/dubbo-demo-consumer-application.configurators
  3. 监听服务的动态配置,即/dubbo/config/dubbo/org.apache.dubbo.demo.DemoService::.configurators

Dubbo源码|二十三、Dubbo服务引入——服务监听

代码中registry.subscribe就是从注册中心中,将服务提供者的信息进行查询,并添加监听。因为我们使用的是Zookeeper作为注册中心,所以subscribe方法会经过FallbackRegistry类的subscribe方法,最终调到ZookeeperRegistry#doSubscribe方法。

// FallbackRegistry 类的subscribe方法
public void subscribe(URL url, NotifyListener listener) {
    super.subscribe(url, listener);
    removeFailedSubscribed(url, listener);
    try {
      	// doSubscribe 是个抽象方法,由子类实现,这里是ZookeeperRegistry
        doSubscribe(url, listener);
    } catch (Exception e) {
        addFailedSubscribed(url, listener);
    }
}

doSubscribe

ZookeeperRegistry类的doSubscribe方法

Dubbo源码|二十三、Dubbo服务引入——服务监听

doSubscribe做了如下几件事:

  1. 调用toCategoriesPath方法,从url中解析category对应的值,对应的值分别为:providersconfiguratorsrouters,也就是在前面添加的值。
  2. 根据providersconfiguratorsrouters这3个值以及服务名,生成要监听的服务路径
  3. 判断zkListeners中是否存在url对应的监听器,如果没有的话则进行新建
  4. 调用zkClient方法创建path节点
  5. path节点添加监听
  6. 调用notify方法,该方法会直接调用listener监听器的notify方法,也就是主动触发通知

notify

Dubbo源码|二十三、Dubbo服务引入——服务监听

notify方法会对传入的参数进行分类,看这个写url时属于providersconfiguratorsrouters中的哪一个,分类是根据url中参数的category属性值来判断的。

如果是configurators,则获取动态配置URL,生成configurators

如果是routers,则生成Router,并添加到路由链中;

如果是providers,则解析出提供者的url

最后调用refreshOverrideAndInvoker方法,进行参数刷新,因为有些参数,消费者和提供者都可以配置,但是消费者的优先级要比提供者的高,所以要覆盖提供者的参数,再将URL转换为Invoker

总结

本文主要介绍Dubbo服务引入——服务监听部分,这部分源码内容比较多也比较绕,所以挑了几部分来介绍,由于本人水平有限未能面面俱到,还请较量。