EventDispatcher.fireEvent(new ConfigDataChangeEvent(true, dataId, group, tenant, time.getTime()));

跟着代码一步步往下看:

public class EventDispatcher {

    /**
* add event listener
*/
static public void addEventListener(AbstractEventListener listener) {
for (Class<? extends Event> type : listener.interest()) {
getEntry(type).listeners.addIfAbsent(listener);
}
} /**
* fire event, notify listeners.
*/
static public void fireEvent(Event event) {
if (null == event) {
throw new IllegalArgumentException();
} for (AbstractEventListener listener : getEntry(event.getClass()).listeners) {
try {
listener.onEvent(event);
} catch (Exception e) {
log.error(e.toString(), e);
}
}
}

这个getEntry(event.getClass()).listeners需要重点看下

/**
* get event listener for eventType. Add Entry if not exist.
*/
static Entry getEntry(Class<? extends Event> eventType) {
for (; ; ) {
for (Entry entry : LISTENER_HUB) {
if (entry.eventType == eventType) {
return entry;
}
} Entry tmp = new Entry(eventType);
/**
* false means already exists
*/
if (LISTENER_HUB.addIfAbsent(tmp)) {
return tmp;
}
}
}
    static final CopyOnWriteArrayList<Entry> LISTENER_HUB = new CopyOnWriteArrayList<Entry>();

这个LISTENER_HUB 会预先把几个相应的Entry 加载进去(这个我们后面分析),然后就开始onEvent,通知Listeners了;

@Service
public class AsyncNotifyService extends AbstractEventListener { @Override
public List<Class<? extends Event>> interest() {
List<Class<? extends Event>> types = new ArrayList<Class<? extends Event>>();
// 触发配置变更同步通知
types.add(ConfigDataChangeEvent.class);
return types;
} @Override
public void onEvent(Event event) { // 并发产生 ConfigDataChangeEvent
if (event instanceof ConfigDataChangeEvent) {
ConfigDataChangeEvent evt = (ConfigDataChangeEvent)event;
long dumpTs = evt.lastModifiedTs;
String dataId = evt.dataId;
String group = evt.group;
String tenant = evt.tenant;
String tag = evt.tag;
   // listen的服务地址
List<?> ipList = serverListService.getServerList(); // 其实这里任何类型队列都可以
Queue<NotifySingleTask> queue = new LinkedList<NotifySingleTask>();
for (int i = 0; i < ipList.size(); i++) {
queue.add(new NotifySingleTask(dataId, group, tenant, tag, dumpTs, (String)ipList.get(i), evt.isBeta));
}
EXCUTOR.execute(new AsyncTask(httpclient, queue));
}
}

把这个配置关联的服务一个个通知下,建议大家可以结合观察者模式来理解这个;

    private static final Executor EXCUTOR = Executors.newScheduledThreadPool(100, new NotifyThreadFactory());

然后把这个通知服务扔到县线程池,放到另外一个线程中去执行通知任务;

 class AsyncTask implements Runnable {

        public AsyncTask(CloseableHttpAsyncClient httpclient, Queue<NotifySingleTask> queue) {
this.httpclient = httpclient;
this.queue = queue;
} @Override
public void run() { executeAsyncInvoke(); } private void executeAsyncInvoke() {
while (!queue.isEmpty()) { NotifySingleTask task = queue.poll();
String targetIp = task.getTargetIP();
if (serverListService.getServerList().contains(
targetIp)) {
// 启动健康检查且有不监控的ip则直接把放到通知队列,否则通知
if (serverListService.isHealthCheck()
&& ServerListService.getServerListUnhealth().contains(targetIp)) {
// target ip 不健康,则放入通知列表中
ConfigTraceService.logNotifyEvent(task.getDataId(), task.getGroup(), task.getTenant(), null,
task.getLastModified(),
LOCAL_IP, ConfigTraceService.NOTIFY_EVENT_UNHEALTH, 0, task.target);
// get delay time and set fail count to the task
int delay = getDelayTime(task);
Queue<NotifySingleTask> queue = new LinkedList<NotifySingleTask>();
queue.add(task);
AsyncTask asyncTask = new AsyncTask(httpclient, queue);
((ScheduledThreadPoolExecutor)EXCUTOR).schedule(asyncTask, delay, TimeUnit.MILLISECONDS);
} else {
HttpGet request = new HttpGet(task.url);
request.setHeader(NotifyService.NOTIFY_HEADER_LAST_MODIFIED,
String.valueOf(task.getLastModified()));
request.setHeader(NotifyService.NOTIFY_HEADER_OP_HANDLE_IP, LOCAL_IP);
if (task.isBeta) {
request.setHeader("isBeta", "true");
}
httpclient.execute(request, new AyscNotifyCallBack(httpclient, task));
}
}
}
} private Queue<NotifySingleTask> queue;
private CloseableHttpAsyncClient httpclient; }

上面这段代码明天再慢慢解析吧,加油!

Nacos深入浅出(三)的更多相关文章

  1. Nacos系列:Nacos的三种部署模式

    三种部署模式 Nacos支持三种部署模式 1.单机模式:可用于测试和单机使用,生产环境切忌使用单机模式(满足不了高可用) 2.集群模式:可用于生产环境,确保高可用 3.多集群模式:可用于多数据中心场景 ...

  2. Nacos(三):Nacos与OpenFeign的对接使用

    前言 上篇文章中,简单介绍了如何在SpringCloud项目中接入Nacos作为注册中心,其中服务消费者是通过RestTemplate+Ribbon的方式来进行服务调用的. 实际上在日常项目中服务间调 ...

  3. Spring Cloud Alibaba 教程 | Nacos(三)

    使用Nacos作为配置中心 前面我们已经介绍过滤Nacos是一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台.所以它可以作为注册中心和配置中心,作为注册中心Nacos可以让我们灵活配置多 ...

  4. PostgreSQL VACUUM 之深入浅出 (三)

    VACUUM 相关参数 对 VACUUM 有了一定的了解之后,下面系统介绍下 VACUUM 相关参数. VACUUM 相关参数主要分为三大类. 第一类 与资源相关参数 #--------------- ...

  5. Nacos深入浅出(十)

    基本上到第9篇,整个请求的一套就结束了,感觉这里跳跳绕绕很多东西,下面我们来做个总结:从Nacos配置平台修改,到Client请求更新,事件触发去取值返回给客户端,整个过程感觉只分析到了4.5层的深度 ...

  6. Nacos深入浅出(九)

    然而Nacos的发布操作并不是上面我们想的那样通过代理去实现,通过下面的代码我们分析下: public class NacosConfigurationPropertiesBindingPostPro ...

  7. VC++动态链接库(DLL)编程深入浅出(三)

    前面我们对非MFC DLL进行了介绍,这一节将详细地讲述MFC规则DLL的创建与使用技巧. 另外,自从本文开始连载后,收到了一些读者的e-mail.有的读者提出了一些问题,笔者将在本文的最后一次连载中 ...

  8. Nacos深入浅出(八)

    Nacos-spring-context.java 感觉这个后台要比之前的Nacos复杂多了,涉及到很多基础的概念,慢慢看,这个后面慢慢更新解析过程 看到他的目录结构一个是基于注解,一个是XML的解析 ...

  9. Nacos深入浅出(七)

    大家可以把这个也下载下来,结合之前的Nacos一起来看下,感觉前面几篇看了好像冰山一角的感觉 学无止境! https://github.com/nacos-group/nacos-spring-pro ...

随机推荐

  1. 如何使用安信可 ESP 系列一体化开发环境【转】

    本文转载自:http://wiki.ai-thinker.com/ai_ide_use 关于 Problems 报错 注意:Eclipse 只是一个代码编写工具,它并不能读取 makefile 里面的 ...

  2. Python —— 批量替换指定目录下的所有文件中指定字符串

    参考:http://blog.csdn.net/zcwfengbingdongguke/article/details/13951527 代码: #!/usr/bin/python import os ...

  3. <算法导论>高级数据结构--以我的角度看B树(Balanced-Tree)的建增删查

    题外话:在博客园看了几篇关于B树的博文确实很有帮助,但是也看到有一些Funny的博文- -比如拿二叉树堂(BinaryTree)而皇之写上B树的帽子. 好了题归正传,B树(Balanced-Tree) ...

  4. tensorflow kmeans 聚类

    iris: # -*- coding: utf-8 -*- # K-means with TensorFlow #---------------------------------- # # This ...

  5. Qt容器组件(二)之QWidgetStack、QMdiArea、QDockWidget

    QT中有九种容器组件,分别是组合框QGroupBox.滚动区QScrollArea.工具箱QToolBox.选项卡QTabWidget.控件栈QWidgetStack.框架QFrame.组件QWidg ...

  6. Katalon Recorder 自动录制 Selenium 爬虫脚本

    相信很多小伙伴都用过 Selenium 来完成爬虫工作,今天就给大家带来一个神器,可以录制你的浏览器动作,然后直接生成 Selenium 脚本,是不是心动了? 1 Selenium 简介 Seleni ...

  7. 递归/非递归----python深度遍历二叉树(前序遍历,中序遍历,后序遍历)

    递归代码:递归实现很简单 '二叉树结点类' class TreeNode: def __init__(self, x): self.val = x self.left = None self.righ ...

  8. AtCoder Grand Contest #026 C - String Coloring

    Time Limit: 3 sec / Memory Limit: 1024 MB Score : 600600 points Problem Statement You are given a st ...

  9. 监测GPU使用情况命令

    每2秒监测一次:watch -n 2 nvidia-smi

  10. javacpp-FFmpeg系列之3: 像素图像数据转换(BGR与BufferdImage互转,RGB与BufferdImage互转,BufferdImage转Base64编码)

    javacpp-ffmpeg系列: javacpp-FFmpeg系列之1:视频拉流解码成YUVJ420P,并保存为jpg图片 javacpp-FFmpeg系列之2:通用拉流解码器,支持视频拉流解码并转 ...