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. WebsiteCrawler

    看到网上不少py的爬虫功能极强大,可惜对py了解的不多,以前尝试过使用c# WebHttpRequert类来读取网站的html页面源码,然后通过正则表达式筛选出想要的结果,但现在的网站中,多数使用js ...

  2. LightOJ - 1038 Race to 1 Again —— 期望

    题目链接:https://vjudge.net/problem/LightOJ-1038 1038 - Race to 1 Again    PDF (English) Statistics Foru ...

  3. make和rest用法

    位置(position):下一个要读取或写入的数据的索引.缓冲区的位置不能为负,并且不能大于其限制(limit). 标记(mark)与重置(reset):标记是一个索引,通过Buffer中的mark( ...

  4. html5--1.10绝对路径和相对路径

    html5--1.10绝对路径和相对路径 学习要点: 绝对路径和相对路径 1.绝对路径 需要指出链接资源的绝对位置,与你的HTML文档的位置无关: 1. 服务器中的位置:href="http ...

  5. 剑指OFFER18 判断一个二叉树的子树

    public class a18_IsSubTree { public static boolean hasSubTree(TreeNode treeRoot1, TreeNode treeRoot2 ...

  6. linux 进程学习笔记-暂停进程

    <!--[if !supportLists]-->Ÿ <!--[endif]-->暂停进程 int pause() 其会挂起当前进程直到有信号来唤醒或者进程被结束. 随便提一下 ...

  7. homebrew cask安装launch rocket【转】

    简介 brew cask是一个用命令行管理Mac下应用的工具,它是基于homebrew的一个增强工具. homebrew可以管理Mac下的命令行工具,例如imagemagick, nodejs,如下所 ...

  8. HihoCoder1656 : 前缀后缀查询([Offer收割]编程练习赛39)(字典树+小技巧)

    描述 给定一个包含N个单词的字典:{W1, W2, W3, ... WN},其中第i个单词Wi有具有一个权值Vi. 现在小Hi要进行M次查询,每次查询包含一个前缀字符串Pi和一个后缀字符串Si.他希望 ...

  9. Linux中vsftpd安装和配置

    目录 Redhat/CentOS安装vsftp软件 Ubuntu/Debian安装vsftp软件 Redhat/CentOS安装vsftp软件 1. 安装vsftp $ yum install vsf ...

  10. rman理论(一)

    1) 快照控制文件:开始备份后,RMAN 需要这些信息在备份操作期间保持一致,也就是说RMAN需要一个读取一致的控制文件视图. 除非RMAN 在备份持续时间内锁定控制文件,否则数据库会不断更新控制文件 ...