Nacos深入浅出(三)
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深入浅出(三)的更多相关文章
- Nacos系列:Nacos的三种部署模式
三种部署模式 Nacos支持三种部署模式 1.单机模式:可用于测试和单机使用,生产环境切忌使用单机模式(满足不了高可用) 2.集群模式:可用于生产环境,确保高可用 3.多集群模式:可用于多数据中心场景 ...
- Nacos(三):Nacos与OpenFeign的对接使用
前言 上篇文章中,简单介绍了如何在SpringCloud项目中接入Nacos作为注册中心,其中服务消费者是通过RestTemplate+Ribbon的方式来进行服务调用的. 实际上在日常项目中服务间调 ...
- Spring Cloud Alibaba 教程 | Nacos(三)
使用Nacos作为配置中心 前面我们已经介绍过滤Nacos是一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台.所以它可以作为注册中心和配置中心,作为注册中心Nacos可以让我们灵活配置多 ...
- PostgreSQL VACUUM 之深入浅出 (三)
VACUUM 相关参数 对 VACUUM 有了一定的了解之后,下面系统介绍下 VACUUM 相关参数. VACUUM 相关参数主要分为三大类. 第一类 与资源相关参数 #--------------- ...
- Nacos深入浅出(十)
基本上到第9篇,整个请求的一套就结束了,感觉这里跳跳绕绕很多东西,下面我们来做个总结:从Nacos配置平台修改,到Client请求更新,事件触发去取值返回给客户端,整个过程感觉只分析到了4.5层的深度 ...
- Nacos深入浅出(九)
然而Nacos的发布操作并不是上面我们想的那样通过代理去实现,通过下面的代码我们分析下: public class NacosConfigurationPropertiesBindingPostPro ...
- VC++动态链接库(DLL)编程深入浅出(三)
前面我们对非MFC DLL进行了介绍,这一节将详细地讲述MFC规则DLL的创建与使用技巧. 另外,自从本文开始连载后,收到了一些读者的e-mail.有的读者提出了一些问题,笔者将在本文的最后一次连载中 ...
- Nacos深入浅出(八)
Nacos-spring-context.java 感觉这个后台要比之前的Nacos复杂多了,涉及到很多基础的概念,慢慢看,这个后面慢慢更新解析过程 看到他的目录结构一个是基于注解,一个是XML的解析 ...
- Nacos深入浅出(七)
大家可以把这个也下载下来,结合之前的Nacos一起来看下,感觉前面几篇看了好像冰山一角的感觉 学无止境! https://github.com/nacos-group/nacos-spring-pro ...
随机推荐
- poj 1146 ID Codes (字符串处理 生成排列组合 生成当前串的下一个字典序排列 【*模板】 )
ID Codes Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 6229 Accepted: 3737 Descript ...
- SDUT OJ 河床
河床 Time Limit: 3000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 地理学家们经常要对一段河流进行测量分析.他们从上游开始向下游方向等距离地选择 ...
- POJ1625 Censored! —— AC自动机 + DP + 大数
题目链接:https://vjudge.net/problem/POJ-1625 Censored! Time Limit: 5000MS Memory Limit: 10000K Total S ...
- Linux学习之路(四)帮助命令
帮助命令man .man 命令 #获取指定命令的帮助 .man ls #查看ls的帮助 man的级别 1 查看命令的帮助 2 查看可被内核调用的函数的帮助 3 查看函数的函数库的帮助 4 查看特殊文件 ...
- 如何用命令行删除EasyBCD开机选择项?
用硬盘安装Ubuntu方法的windows双系统电脑上面,很多人都是用EasyBCD设置的开机启动选择.所以当我们不需要双系统的时候,或者已经删除双系统后,或者安装双系统失败的情况下,发现电脑的开机启 ...
- python循环次数的使用
a=[str(i) for i in range(88888,88912)] b=[str(i) for i in range(77777,77785)] def f(a,b,k=0,m=0): n= ...
- 按钮滚动到指定位置(JS)
function intval(v) { v = parseInt(v); return isNaN(v) ? 0 : v; } function getPos(e) { var l = 0; var ...
- codeforces 659B B. Qualifying Contest(水题+sort)
题目链接: B. Qualifying Contest time limit per test 1 second memory limit per test 256 megabytes input s ...
- 如何在u盘上安装系统, (非安装盘)
在u盘中永久安装Fedora. 需要两个u盘(live usb), 一个系统镜像文件. 方法是: 用一个u盘作安装盘, 然后通过这个u盘把系统安装到另一个u盘上. 两个U盘上的文件都会被覆盖. 1. ...
- linux 进程学习笔记-进程调度
在分时系统中,系统将CPU时间划分成无数个时间片(quantum)分配给不同的进程,一个时间片只执行一个进程,并且不停地切换,以让用户感觉到各个进程是在“同时运行”,这中间所需要的策略和算法便是进程调 ...