Dubbo源码|十八、Dubbo服务暴露—服务监听

1,197 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第22天,点击查看活动详情

开篇

本文介绍Dubbo服务的监听。

Dubbo服务暴露(一)

Dubbo服务暴露(二)

Dubbo服务暴露(三)

Dubbo服务暴露(四)

Dubbo服务暴露(五)

Dubbo服务暴露(六)

说到监听,那么作为一个服务提供者,到底要监听什么东西呢?

服务提供者主要监听的是动态配置,例如在dubbo-admin中对服务进行更改,服务提供者是需要感知到的。

动态配置包括服务的动态配置、应用的动态配置。以Zookeeper为例,这些动态配置在Zookeeper的存储路径为:

应用的动态配置:

/dubbo/config/dubbo/dubbo-demo-provier-application.configurators

服务的动态配置:

/dubbo/config/dubbo/org.apache.dubbo.DemoService::.configurators

应用的动态配置(老版本):

/dubbo/dubbo/org.apache.dubbo.DemoService/configurators

当这些动态配置数据发生改变时,对应的服务也会跟着改变。

监听器

还记得前面说的监听器初始化入口在哪里吗?初始化入口是在RegistryProtocol#export方法中。

final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);

providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);

private URL overrideUrlWithConfig(URL providerUrl, OverrideListener listener) {
    providerUrl = providerConfigurationListener.overrideUrl(providerUrl);
    ServiceConfigurationListener serviceConfigurationListener = new ServiceConfigurationListener(providerUrl, listener);
    serviceConfigurationListeners.put(providerUrl.getServiceKey(), serviceConfigurationListener);
    return serviceConfigurationListener.overrideUrl(providerUrl);
}

OverrideListener这个类实现了NotifyListener接口,当有配置改动时,就会回调这个类的notify方法。

providerConfigurationListener是针对应用级别的监听,serviceConfigurationListeners是针对服务级别的监听,因为服务可以有多个所以是个集合类型。

应用监听器

public ProviderConfigurationListener() {
    this.initWith(ApplicationModel.getApplication() + CONFIGURATORS_SUFFIX);
}
protected final void initWith(String key) {
    ruleRepository.addListener(key, this);
    String rawConfig = ruleRepository.getRule(key, DynamicConfiguration.DEFAULT_GROUP);
    if (!StringUtils.isEmpty(rawConfig)) {
        genConfiguratorsFromRawRule(rawConfig);
    }
}

方法中的key就是监听的路径,例如dubbo-demo-annotation-provider.configuratorsaddListener(key, this)就是对路径进行绑定监听。

rawConfig就是从Zookeeper注册中心读取到的原始配置参数,例如:

configVersion: v2.7
configs:
- addresses:
  - 0.0.0.0
  enabled: false
  parameters:
    timeout: 6000
  side: provider
enabled: true
key: dubbo-demo-annotation-provider
scope: application

拿到配置参数后,会把参数解析为一个configurators对象。然后再调用providerConfigurationListener.overrideUrl方法对传进来的URL进行重写,替换掉对应的参数,比如在dubbo-admin中添加了动态参数设置timeout为6s,调用overrideUrl方法,就会把providerUrl中原有的timeout值给覆盖掉。

服务监听器

image.png

image.png

同样的,服务监听器在初始化的时候,也会与一个路径进行绑定,先获取注册中心中配置的内容,并进行解析。调用ServiceConfigurationListener类的overrideUrl方法进行URL参数的重写。

可以看到,providerConfigurationListenerServiceConfigurationListener都会对URL进行重写,但是ServiceConfigurationListener是后处理的,所以可以得出结论:服务的配置优先级更高

老版本的服务监听

registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);

老版本Dubbo服务的监听是这个方法处理的,处理方法的原理都是一样的,这里就不再赘述。 老版本是指dubbo 2.6.x 以及前的版本。

服务监听示例

刚发看到了服务监控器实例化的过程,下面来操作一遍看监听是如何触发的。监听通知的方法在ServiceConfigurationListenernotifyOverrides方法中,我们来打一个断点,然后更改监听的内容。

image.png

将服务的超时时间更改为3001,点击保存。

image.png 我们看到ServiceConfigurationListener就接收到了通知。

URL重写

image.png

接收到通知后,对URL的重写过程如下:

  1. 获取原始的服务URL(originUrl),未经过任何改变的URL。
  2. 获取当前服务的URL(currentUrl),当前处理的URL,可能之前被更改过。
  3. 对原始URLoriginUrl进行重写,这里重写会经过3次重写,老版本的重写、应用级别的重写、服务级别的重新,重写后得到一个newUrl
  4. newUrlcurrentUrl进行对别,如果不一致的话,这进行服务的重新导出。

重新导出

image.png

该方法主要处理过程如下:

  1. 对新URL服务进行导出。
  2. 获取原来的注册URL、新的注册URL,进行对比。
  3. 如果不一致,将原来的URL对应服务执行卸载unregister
  4. 将新的URL进行注册到注册中心,并更新缓存。

需要注意的是,重新导出与原来的导出逻辑基本一致,唯一不同的是由于第一次导出时ProtocolServer对象被缓存了,所以在重新导出时,调用的是server.reset(url)进行导出的,具体代码在DubboProtocol#openServer

image.png

后记

本文主要介绍了服务对动态配置的逻辑处理以及服务的重新导出,欢迎一起交流。