小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
ClientLongPolling
ClientLongPolling是一个线程,其run方法的代码如下:
- 通过scheduler.schedule启动一个定时任务,并且延时时间为29.5s
- 将ClientLongPolling实例添加allSubs队列中,它主要维护一个长轮询的订阅关系
- 定时任务执行后,先把ClientLongPolling实例从allSubs队列中移除
- 通过MD5比较客户端请求的groupKeys是否发生了变更,并将变更的结果通过response返回给客户端
class ClientLngPolling implements Runnable{
@Override
public void run(){
//启动定时任务
scheduler.schedule(new Runnable(){
@Override
public void run(){
try{
asyncTimeoutFuture=getRetainIps().put(ClientLongPolling.this.ip,System.currentTimeMillis());
allSubs.remove(ClientLongPolling.this);
if(isFixedPolling(){
//比较数据的md5值判断是否发生了修改
List<String> changedGroups = MD5Util.compareMd5((HttpServletRequest)asyncCOntext.getRequest(),(HttpServletResponse)asyncContext.getResponse,clientMd5Map);
if(changedGroups.size()>0){
sendResponse(changedGroups);
}else{
sendResponse(null);
}
}else{
sendResponse(null);
}
}catch(Throwable t){
LogUtil.defaultLog.error("long polling error:"+t.getMessage(),t.getCause());
}
}
},timeoutTime,TimeUnit.MILLSECONDS);
allSubs.add(this);
}
}
从以上代码分析,长轮询就是服务端收到请求后,不立即返回,而是在延时后29.5s才把请求结果返回给客户端,客户端和服务端之间在30s之内数据没有修改下一直处于连接状态。 当通过控制台或OpenAPI的方式修改配置后,如何实时通知呢?定时任务是延迟29.5s执行,没有达到以上的实时通知的结果。通过类图发现,LongPollingService继承了AbstractEventListener
AbstractEventListener是一个事件抽象类,它有一个onEvent抽象方法,而LongPollingService实现了以下方法:
@Override
public void onEvent(Event event){
if(isFixedPolling()){
}else{
if(event instanceof LocalDataChangeEvent){
LocalDataChangeEvent localDataChangeEvent=(LocalDataChangeEvent)event;
scheduler.execute(new DataChangeTask(localDataChangeEvent.groupKey,localDataChangeEvent.isBeta,localDataChangeEvent.betaIps));
}
}
}
涉及到事件处理机制,LongPollingService的onEvent方法看到一个LocalDataChangeEvent事件,这事件是在服务端的配置数据修改时发布一个事件,接着关注收到事件后处理行为。