配置中心Apollo

Apollo(2) 长轮询

2022-12-08  本文已影响0人  Oliver_Li
  1. 长链接、长轮询概念:https://blog.csdn.net/joeries/article/details/91389939
  1. DeferredResult:springMvc DeferredResult的long polling应用 | KL博客
  1. DeferredResult原理见博客,下面的代码根据博客代码进行改造,更贴近Apollo长轮询的服务端源码逻辑,模拟了包括Config Service接收Client请求、Config Service接收到Admin Service监听时setResult()返回消息,长轮训是Apollo最重要的逻辑之一
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.Map;

/**
 * 模拟两个Client长轮训请求:localhost:9998/async/longPolling?namespace=namespace1、localhost:9998/async/longPolling?namespace=namespace2
 * 模拟触发监听响应Client:localhost:9998/async/returnLongPollingValue?namespace=namespace1
 */
@RestController
@RequestMapping("/async")
public class DeferredResultController {
    final Map<String, DeferredResult<ResponseEntity<String>>> deferredResultMap = new ConcurrentReferenceHashMap<>(); // 存deferredResult的Map

    private static final ResponseEntity<String> STATUS_304 = new ResponseEntity<>(HttpStatus.NOT_MODIFIED); // http 304

    @GetMapping("/longPolling")
    public DeferredResult<ResponseEntity<String>> DeferredResultLongPolling(String namespace) {
        // 初始化DeferredResult,超时5s后返回304,如果被setResult()也会触发响应
        DeferredResult<ResponseEntity<String>> deferredResult = new DeferredResult<>(5000L, STATUS_304);
        // 加入到全局集合deferredResultMap,否则returnLongPollingValue接口获取不到DeferredResult对象
        deferredResultMap.put(namespace, deferredResult);
        System.out.println("deferredResult.hashCode()" + deferredResult.hashCode());
        // 超时、deferredResult.setResult()都会回调onCompletion(),代表Map里的DeferredResult使用结束后必须被清掉
        deferredResult.onCompletion(() -> {
            deferredResultMap.remove(namespace);
            System.err.println("还剩" + deferredResultMap.size() + "个deferredResult未响应");
        });
        // controller会正常执行,但response会被拦住不会返回客户端,超时或者DeferredResult被setResult()才会真正响应给客户端
        return deferredResult;
    }

    @GetMapping("/returnLongPollingValue")
    public void returnLongPollingValue(String namespace) {
        // 模拟Apollo Config Service发布触发listener回调,返回200并带上namespace最新的release message表ID,后续Client会根据ID查具体配置
        DeferredResult<ResponseEntity<String>> deferredResult = deferredResultMap.get(namespace);
        ResponseEntity<String> response = new ResponseEntity<>(namespace + " new release message ID!", HttpStatus.OK);
        deferredResult.setResult(response);
    }
}
上一篇 下一篇

猜你喜欢

热点阅读