DeferredResult 提高系统吞吐量的一把利器

30 篇文章 3 订阅

        当一个接口处理耗时时,为了接口做出快速相应,释放tomcat资源,提高系统的吞吐量,sping3.0 以后引入DeferredResult。

        

代码演示

 @GetMapping("/deferredResult")
    public DeferredResult<Map<String, Object>> test() {
        System.out.println("进入" + Thread.currentThread() + Thread.currentThread().getId());
        DeferredResult<Map<String, Object>> result = new DeferredResult<>();
        new Thread(() -> {
            System.out.println("开始" + Thread.currentThread());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("返回结果" + Thread.currentThread());
            result.setResult(new HashMap<String, Object>() {{
                put("code", "200");
            }});
        }).start();
        System.out.println("返回" + Thread.currentThread() + Thread.currentThread().getId());
        return result;
    }

 

运行讲解

   放入接口没有什么好理解的,就是一个纯粹的一个同步请求接口。主要关注的是对应的返回值为DeferredResult的接口,主要看看内部是如何进行执行的。从org.springframework.web.servlet.DispatcherServlet#doDispatch执行开始进行。

  1. 经过doDispatch后,接下来会到对应的org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler#handleReturnValue中,判断当前返回值类型。
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

   if (returnValue == null) {
      mavContainer.setRequestHandled(true);
      return;
   }

   DeferredResult<?> result;

   if (returnValue instanceof DeferredResult) { // 本Demo中的数据类型
      result = (DeferredResult<?>) returnValue;
   }
   else if (returnValue instanceof ListenableFuture) { // 原有Future的增强
      result = adaptListenableFuture((ListenableFuture<?>) returnValue);
   }
   else if (returnValue instanceof CompletionStage) { // 用于异步执行中的阶段处理
      result = adaptCompletionStage((CompletionStage<?>) returnValue);
   }
   else {
      // Should not happen...
      throw new IllegalStateException("Unexpected return value type: " + returnValue);
   }
    WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(result, mavContainer); // 获得对应异步管理器并执行
}
复制代码
  1. 经过包装返回值的类型,接下来就进行到了请求处理:org.springframework.web.context.request.async.WebAsyncManager#startDeferredResultProcessing
public void startDeferredResultProcessing(
      final DeferredResult<?> deferredResult, Object... processingContext) throws Exception {

   Assert.notNull(deferredResult, "DeferredResult must not be null");
   Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null");

   Long timeout = deferredResult.getTimeoutValue();
   if (timeout != null) {
      this.asyncWebRequest.setTimeout(timeout);
   }
   // 增加拦截器设置   此时只有第一个和第三个(第一个是DeferredResult类中匿名实现)
   List<DeferredResultProcessingInterceptor> interceptors = new ArrayList<>();
   interceptors.add(deferredResult.getInterceptor());
   interceptors.addAll(this.deferredResultInterceptors.values());
   interceptors.add(timeoutDeferredResultInterceptor);

   final DeferredResultInterceptorChain interceptorChain = new DeferredResultInterceptorChain(interceptors);
   // 增加超时  错误  完成回调处理,进行触发
   this.asyncWebRequest.addTimeoutHandler(() -> {
      try {
         interceptorChain.triggerAfterTimeout(this.asyncWebRequest, deferredResult);
      }
      catch (Throwable ex) {
         setConcurrentResultAndDispatch(ex);
      }
   });

   this.asyncWebRequest.addErrorHandler(ex -> {
      if (!this.errorHandlingInProgress) {
         try {
            if (!interceptorChain.triggerAfterError(this.asyncWebRequest, deferredResult, ex)) {
               return;
            }
            deferredResult.setErrorResult(ex);
         }
         catch (Throwable interceptorEx) {
            setConcurrentResultAndDispatch(interceptorEx);
         }
      }
   });

   this.asyncWebRequest.addCompletionHandler(()
         -> interceptorChain.triggerAfterCompletion(this.asyncWebRequest, deferredResult));
   // 请求初始之前的处理 -空实现
   interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, deferredResult);
   // 开始异步调用处理
   startAsyncProcessing(processingContext);

   try {
      // 
      interceptorChain.applyPreProcess(this.asyncWebRequest, deferredResult);
      deferredResult.setResultHandler(result -> {
         result = interceptorChain.applyPostProcess(this.asyncWebRequest, deferredResult, result);
         setConcurrentResultAndDispatch(result);
      });
   }
   catch (Throwable ex) {
      setConcurrentResultAndDispatch(ex);
   }
}
复制代码
  1. 请求接着往下走,会进行到org.apache.catalina.core.AsyncContextImpl#setStarted。在其中进行异步事件处理。
public void setStarted(Context context, ServletRequest request,
        ServletResponse response, boolean originalRequestResponse) {

    synchronized (asyncContextLock) { 
        this.request.getCoyoteRequest().action(ActionCode.ASYNC_START, this); // 异步事件处理 - 钩子函数
        this.context = context;
        context.incrementInProgressAsyncCount();
        this.servletRequest = request;
        this.servletResponse = response;
        this.hasOriginalRequestAndResponse = originalRequestResponse;
        this.event = new AsyncEvent(this, request, response);
        // 注册异步事件监听器 - 当前为空 不进行监听
        List<AsyncListenerWrapper> listenersCopy = new ArrayList<>(listeners);
        listeners.clear();
        if (log.isDebugEnabled()) {
            log.debug(sm.getString("asyncContextImpl.fireOnStartAsync"));
        }
        for (AsyncListenerWrapper listener : listenersCopy) {
            try {
                listener.fireOnStartAsync(event);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.warn(sm.getString("asyncContextImpl.onStartAsyncError",
                        listener.getClass().getName()), t);
            }
        }
    }
}
复制代码
  1. 当异步事件处理完成之后,则会还需要对应Dispatch进行响应。
private void setConcurrentResultAndDispatch(Object result) {
   synchronized (WebAsyncManager.this) {
      if (this.concurrentResult != RESULT_NONE) {
         return;
      }
      this.concurrentResult = result;
      this.errorHandlingInProgress = (result instanceof Throwable);
   }

   if (this.asyncWebRequest.isAsyncComplete()) {
      if (logger.isDebugEnabled()) {
         logger.debug("Async result set but request already complete: " + formatRequestUri());
      }
      return;
   }

   if (logger.isDebugEnabled()) {
      boolean isError = result instanceof Throwable;
      logger.debug("Async " + (isError ? "error" : "result set") + ", dispatch to " + formatRequestUri());
   }
   this.asyncWebRequest.dispatch(); // ASYNC_DISPATCH事件注册
}
复制代码
  1. 判断当前请求是否超时逻辑org.apache.coyote.AbstractProcessor#timeoutAsync:
@Override
public void timeoutAsync(long now) {
    if (now < 0) {
        doTimeoutAsync();
    } else {
        long asyncTimeout = getAsyncTimeout();
        if (asyncTimeout > 0) {
            long asyncStart = asyncStateMachine.getLastAsyncStart();
            if ((now - asyncStart) > asyncTimeout) {
                doTimeoutAsync();
            }
        } else if (!asyncStateMachine.isAvailable()) {
            // Timeout the async process if the associated web application
            // is no longer running.
            doTimeoutAsync();
        }
    }
}


private void doTimeoutAsync() {
    // Avoid multiple timeouts
    setAsyncTimeout(-1);
    asyncTimeoutGeneration = asyncStateMachine.getCurrentGeneration();
    processSocketEvent(SocketEvent.TIMEOUT, true); // 发送timeout事件
}
复制代码
  1. HTTP事件响应可以看看org.apache.coyote.AbstractProcessor#action类中,针对HTTP各种事件进行各种处理(code太多,这里就不贴了)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值