写点什么

Nacos 配置中心之事件订阅

作者:周杰伦本人
  • 2022 年 8 月 02 日
  • 本文字数:1971 字

    阅读完需:约 6 分钟

Nacos 配置中心之事件订阅

我们都知道,Nacos 配置中心支持动态的刷新,有没有想过它是怎么实现的呢?


当配置中心的配置发送 NacosContextRefresher 实现 ApplicationListener 接口进行事件监听,在上下文准备完毕时候触发这个事件


NacosContextRefresher 的 onApplicationEvent 方法:


@Overridepublic void onApplicationEvent(ApplicationReadyEvent event) {   // many Spring context   if (this.ready.compareAndSet(false, true)) {      this.registerNacosListenersForApplications();   }}
复制代码


使用 CAS 加锁,把 ready 变量改为 true


调用 registerNacosListenersForApplications()进行 Nacos 事件监听的注册。


registerNacosListenersForApplications 方法:


private void registerNacosListenersForApplications() {   if (refreshProperties.isEnabled()) {      for (NacosPropertySource nacosPropertySource : NacosPropertySourceRepository            .getAll()) {
if (!nacosPropertySource.isRefreshable()) { continue; }
String dataId = nacosPropertySource.getDataId(); registerNacosListener(nacosPropertySource.getGroup(), dataId); } }}
复制代码


  1. 获取 dataId

  2. 如果属性源不支持刷新就跳过,支持就调用 registerNacosListener()方法,我们看一下这个方法

registerNacosListener()方法

private void registerNacosListener(final String group, final String dataId) {
Listener listener = listenerMap.computeIfAbsent(dataId, i -> new Listener() { @Override public void receiveConfigInfo(String configInfo) { refreshCountIncrement(); String md5 = ""; if (!StringUtils.isEmpty(configInfo)) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md5 = new BigInteger(1, md.digest(configInfo.getBytes("UTF-8"))) .toString(16); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { log.warn("[Nacos] unable to get md5 for dataId: " + dataId, e); } } refreshHistory.add(dataId, md5); applicationContext.publishEvent( new RefreshEvent(this, null, "Refresh Nacos config")); if (log.isDebugEnabled()) { log.debug("Refresh Nacos config group " + group + ",dataId" + dataId); } }
@Override public Executor getExecutor() { return null; } });
try { configService.addListener(dataId, group, listener); } catch (NacosException e) { e.printStackTrace(); }}
复制代码


  1. 创建监听器添加到 listenerMap 集合中,监听器中主要刷新个数,添加 dataId 和 md5 到监听历史中,最后发布监听事件

  2. 把监听器在添加到 configService 中,这篇文章我们有介绍这个类,它是 Nacos 客户端提供的用于访问实现配置中心基本操作的类


registerNacosListener 中 applicationContext.publishEvent 方法发布 RefreshEvent 事件,监听这个事件到实现类在 RefreshEventListener 类中

事件监听

RefreshEventListener 类:


public class RefreshEventListener implements SmartApplicationListener {     private ContextRefresher refresh;
public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationReadyEvent) { this.handle((ApplicationReadyEvent)event); } else if (event instanceof RefreshEvent) { this.handle((RefreshEvent)event); }
} public void handle(RefreshEvent event) { if (this.ready.get()) { log.debug("Event received " + event.getEventDesc()); Set<String> keys = this.refresh.refresh(); log.info("Refresh keys changed: " + keys); }
}
复制代码


handler 方法中调用 refresh.refresh()方法完成配置的更新和应用。

总结

现在我们知道 Nacos 配置中心的时间订阅是怎么回事了,首先 NacosContextRefresher 实现了 ApplicationListener 接口,在上下文准备完毕时候触发事件方法,方法中调用 refresh.refresh()方法来完成配置的更新和应用,对于事件订阅,这里用到的设计模式属于是观察者模式,所以说设计模式在我们的源码中无处不在,阅读源码能让我们学习好的思想,让自己更好的解决工作中的问题,下篇文章中我们将介绍 nacos 的客户端的长轮询机制是怎么工作的,我们下篇文章见吧~

发布于: 刚刚阅读数: 6
用户头像

还未添加个人签名 2020.02.29 加入

公众号《盼盼小课堂》,多平台优质博主

评论

发布
暂无评论
Nacos配置中心之事件订阅_8月月更_周杰伦本人_InfoQ写作社区