前言
dubbo提供服务运行时动态修改配置的功能。
原理是服务消费方和服务提供方都注册时间,监听注册中心上某个服务暴露接口的configurator节点,通过dubbo提供的api注册override协议或者zookeeper api直接修改该节点的内容,客户端监听到之后把修改后的Url中的配置重写到内存中,以达到动态修改服务配置的目的。
![](https://img.haomeiwen.com/i23353704/1561bba9413b8dcb.png)
dubbo override协议 :
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&timeout=1000"));
事件注册时机
在服务提供方或者服务消费方注册服务之后,往zookeeper中的该节点注册监听时间。
源码
接着上一篇 服务暴露方注册服务之后
![](https://img.haomeiwen.com/i23353704/2ca48e2807c33ffa.png)
1、URL从注册协议替换
第一行代码就会把协议从Registry换成provider协议,然后把协议的category属性换成configurator
![](https://img.haomeiwen.com/i23353704/cb1e10f015cc1129.png)
![](https://img.haomeiwen.com/i23353704/8a7b11d33552f6d6.png)
替换后的url
provider://192.168.31.211:20880/com.lb.dubbo_api.service.UserService?anyhost=true&application=dubbo-p&bean.name=ServiceBean:com.lb.dubbo_api.service.UserService
&category=configurators
&check=false&dubbo=2.0.2&generic=false&interface=com.lb.dubbo_api.service.UserService&methods=getUser&pid=60975&side=provider×tamp=1626103040686
2. 创建OverrideListener对象
OverrideListener接口
dubbo抽象的监听器,只有一个notify方法,用来执行触发监听后执行业务逻辑的
![](https://img.haomeiwen.com/i23353704/afd3e51321df6e37.png)
OverrideListener类实现了上述接口,持有订阅事件的url协议和invoker对象
![](https://img.haomeiwen.com/i23353704/f2ffaa839e2f8fdb.png)
通过构造器new,传入url协议和invoker对象
![](https://img.haomeiwen.com/i23353704/ada471b75ada62ec.png)
放入缓存,url -> overrideListener实例的缓存
![](https://img.haomeiwen.com/i23353704/ebcde2d1b52d95db.png)
3. 注册事件
目前只new出了dubbo的监听器实例,还没有注册到zookeper。
![](https://img.haomeiwen.com/i23353704/e341408401f222a0.png)
3.1. 建立overrideListener和zookeeper监听器实例的映射
上面这行代码,调父类AbstractRegistry的subscribe建立缓存
![](https://img.haomeiwen.com/i23353704/eb0f6781b90ceb5f.png)
![](https://img.haomeiwen.com/i23353704/f172b4aa4dee96d5.png)
缓存映射关系
URL : ConcurrentHashSet<NotifyListener>
3.2. 注册事件核心
第一个判断不会走,因为我们的接口类是具体的接口,而不是 *
![](https://img.haomeiwen.com/i23353704/0582f5388ba404ed.png)
else
又是一个缓存容器
![](https://img.haomeiwen.com/i23353704/b2462b530866529b.png)
url :{NotifyListener : ChildListener}
第一次进来根据NotifyListener肯定拿不到ChildListener实例,所以走创建
![](https://img.haomeiwen.com/i23353704/a921781638c17131.png)
3.2.1 ChildListener
只有一个childChanged方法
![](https://img.haomeiwen.com/i23353704/f209e912da01ff3a.png)
注意new ChildListener实例的时候,是把notifyListener传进去的
并且实现的childChanged方法,会调用传入的notifyListener的notify方法
![](https://img.haomeiwen.com/i23353704/aedc01b62a41da2f.png)
3.2.2 往zk创建configurator持久节点
zk节点路径
/dubbo/com.lb.dubbo_api.service.UserService/configurators
![](https://img.haomeiwen.com/i23353704/350543ef25d386d6.png)
当然,里面会判断是否已存在此节点,没有才会创建
![](https://img.haomeiwen.com/i23353704/b96cf37adce4e494.png)
3.2.3 注册zk事件
![](https://img.haomeiwen.com/i23353704/95ac8213fbdf5e39.png)
一进来又是一个缓存容器
ChildListener : TargetChildListener(泛型)
![](https://img.haomeiwen.com/i23353704/ddcc4b113f525a7a.png)
创建curator的的CuratorWatcher时间监听实例
这里的TargetChildListener泛型在这里就是zk客户端curator的事件监听器实现类Watcher,因为后续就会往缓存容器中put :
childListener -> new CuratorWatcherImpl(childListener)
![](https://img.haomeiwen.com/i23353704/a9cbfc4a934d436f.png)
构造器中持有的是childListener
![](https://img.haomeiwen.com/i23353704/8b11394a60c660b0.png)
这里就会掉用ChildListener事件的方法
![](https://img.haomeiwen.com/i23353704/b5f568171f46693c.png)
注册事件 :CuratorWatcherImpl
用Curator的api注册事件
![](https://img.haomeiwen.com/i23353704/2144411cfe79ed31.png)
事件触发监听调用流程
前面讲到
childerListener的childChanged会调用到overrideListener的Notity方法,并且持有了overrideListener实例
curator的事件监听实例CuratorWatcherImpl的process会响应监听,并且他持有了childerListener实例,process方法中会调用childerListener的childChanged方法。
所以整体的事件监听触发调用流程是这样的
首先zookeeper基于长链接,调用zk客户端的CuratorWatcherImpl的process方法,然后process方法调用childerListener的childChanged(),然后childChanged()去调用overrideListener的notify(),完成curator事件监听到dubbo事件监听的代码流转
CuratorWatcherImpl.process(event) ->
ChildListener.childChanged() ->
NotifyListener.notify()
最终根据zk configurator节点更新后的配置信息,去覆盖内存中的配置信息,都在NotifyListener.notify()实现的。
网友评论