建议先看下面这篇文章,再看本文
Nacos2.X 服务注册、服务发现详解
为订阅者进行推送
从上面可知,我们在进行服务注册时最后会发布一个ServiceChangedEvent事件。在服务发现时,进行订阅服务的最后会发布一个ServiceSubscribedEvent事件。
我们能大致猜测:当一个服务的实例进行了更新,那么是不是应该推送给所有订阅了该服务的客户端?当我订阅了某个服务,是不是应该将该服务信息推送给我?
我们接下来就来看看这两个事件是如何进行处理的。
服务注册与服务订阅流程中发布的事件最终会被NamingSubscriberServiceV2Impl.onEvent()中进行处理:
- 如果是服务改变,那么就要推送给所有的订阅者
- 如果是服务订阅者事件,那么就只给这一个订阅者进行推送即可
- 最终都会调用到
NacosDelayTaskExecuteEngine类的addTask()方法
@Override
public void onEvent(Event event) {
if (!upgradeJudgement.isUseGrpcFeatures()) {
return;
}
if (event instanceof ServiceEvent.ServiceChangedEvent) {
// 如果是服务改变,那么就要推送给所有的订阅者,所以下面创建PushDelayTask对象的构造方法中只有两个参数
ServiceEvent.ServiceChangedEvent serviceChangedEvent = (ServiceEvent.ServiceChangedEvent) event;
Service service = serviceChangedEvent.getService();
// 创建PushDelayTask对象的构造方法中只有两个参数
delayTaskEngine.addTask(service, new PushDelayTask(service, PushConfig.getInstance().getPushTaskDelay()));
} else if (event instanceof ServiceEvent.ServiceSubscribedEvent) {
// 如果是服务订阅者事件,那么就只给这一个订阅者进行推送即可,所以下面创建PushDelayTask对象的构造方法中只有三个参数
ServiceEvent.ServiceSubscribedEvent subscribedEvent = (ServiceEvent.ServiceSubscribedEvent) event;
Service service = subscribedEvent.getService();
// 创建PushDelayTask对象的构造方法中只有三个参数,最后一个参数是订阅者的ClientId
delayTaskEngine.addTask(service, new PushDelayTask(service, PushConfig.getInstance().getPushTaskDelay(),
subscribedEvent.getClientId()));
}
}
// 我们来看看PushDelayTask对象的两个构造方法
public class PushDelayTask extends AbstractDelayTask {
...
public PushDelayTask(Service service, long delay) {
this.service = service;
// 推送给所有订阅者标识为true,推送给某个目标订阅者为null
pushToAll = true;
targetClients = null;
setTaskInterval(delay);
setLastProcessTime(System.currentTimeMillis());
}
public PushDelayTask(Service service, long delay, String targetClient) {
this.service = service;
// 推送给所有订阅者标识为false,推送给某个目标订阅者为构造方法传过来的ClientId
this.pushToAll = false;
this.targetClients = new HashSet<>(1);
this.targetClients.add(targetClient);
setTaskInterval(delay);
setLastProcessTime(System.currentTimeMillis());
}
}
我们现在再来看看NacosDelayTaskExecuteEngine类的addTask()方法中是做了什么:
- 构造方法中创建一个定时任务,定期的去执行
processTasks()方法 addTask()方法就把我们上方PushDelayTask存入tasks这个集合中。注意PushDelayTask它是AbstractDelayTask的子类processTasks()方法中会从tasks集合中取出所有的AbstractDelayTask,循环处理,通过AbstractDelayTask找各自对应的处理类去进行处理
public class NacosDelayTaskExecuteEngine extends AbstractNacosTaskExecuteEngine<AbstractDelayTask> {
protected final ConcurrentHashMap<Object, AbstractDelayTask> tasks;
......
// 构造方法中会执行一个定时任务
public NacosDelayTaskExecuteEngine(String name, int initCapacity, Logger logger, long processInterval) {
super(logger);
tasks = new ConcurrentHashMap<>(initCapacity);
processingExecutor = ExecutorFactory.newSingleScheduledExecutorService(new NameThreadFactory(name));
// 该类初始化时会执行一个定时任务:ProcessRunnable,在该类的run()方法中会调用下面processTasks()方法
processingExecutor
.scheduleWithFixedDelay(new ProcessRunnable(), processInterval, processInterval, TimeUnit.MILLISECONDS);
}
......
// addTask()方法中仅仅是把我们传递过来的AbstractDelayTask对象存入一个Map集合中
@Override
public void addTask(Object key, AbstractDelayTask newTask) {
lock.lock();
try {
AbstractDelayTask existTask = tasks.get(key);
if (null != existTask) {
newTask.merge(existTask);
}
// 这里会把AbstractDelayTask存进去
tasks.put(key, newTask);
} finally {
lock.unlock();
}
}
// 这里会每个一段时间定时执行,从集合中取出所有的AbstractDelayTask去进行处理
protected void processTasks() {
// 这里会把AbstractDelayTask全取出来进行处理
Collection<Object> keys = getAllTaskKeys();
// 遍历
for (Object taskKey : keys) {
AbstractDelayTask task = removeTask(taskKey);
if (null == task) {
continue;
}
// 根据不同不同类型的AbstractDelayTask,找对应的处理类
NacosTaskProcessor processor = getProcessor(taskKey);
if (null == processor) {
getEngineLog().error("processor not found for task, so discarded. " + task);
continue;
}
try {
// 再调用各自对应的处理类的process()方法
if (!processor.process(task)) {
retryFailedTask(taskKey, task);
}
} catch (Throwable e) {
getEngineLog().error("Nacos task execute error ", e);
retryFailedTask(taskKey, task);
}
}
}
......
}
因为我们这里的是AbstractDelayTask的子类PushDelayTask类,它对应的处理类是PushDelayTaskProcessor。如下所示,就会进入到这里的process()
- 该类会创建PushExecuteTask任务并执行
private static class PushDelayTaskProcessor implements NacosTaskProcessor {
...
@Override
public boolean process(NacosTask task) {
// 强转,转换为最初的PushDelayTask类型
PushDelayTask pushDelayTask = (PushDelayTask) task;
// 取出service对象
Service service = pushDelayTask.getService();
// 从下面的方法名我们就可以看出来这又是异步执行一个task任务,所以我们重点关注new PushExecuteTask()这个类的run()方法
NamingExecuteTaskDispatcher.getInstance()
.dispatchAndExecuteTask(service, new PushExecuteTask(service, executeEngine, pushDelayTask));
return true;
}
}
PushExecuteTask类的run()方法
- 根据
delayTask.isPushToAll()来判断是否要推送当前服务的所有订阅者,返回所有订阅者或某一个订阅者 - 推送NacosClient
public class PushExecuteTask extends AbstractExecuteTask {
private final Service service;
private final PushDelayTaskExecuteEngine delayTaskEngine;
private final PushDelayTask delayTask;
public PushExecuteTask(Service service, PushDelayTaskExecuteEngine delayTaskEngine, PushDelayTask delayTask) {
this.service = service;
this.delayTaskEngine = delayTaskEngine;
this.delayTask = delayTask;
}
@Override
public void run() {
// 将封装了service信息的wrapper推送给客户端
try {
PushDataWrapper wrapper = generatePushData();
ClientManager clientManager = delayTaskEngine.getClientManager();
// 根据 delayTask.isPushToAll() 来判断是否要推送当前服务的所有订阅者,返回所有订阅者或某一个订阅者
for (String each : getTargetClientIds()) {



2340

被折叠的 条评论
为什么被折叠?



