直播带货源码,异步处理中会处理两次请求

直播带货源码,异步处理中会处理两次请求

在这里插入图片描述
从序列图上可以看到SpringMVC在处理异步请求时,DispatcherServlet会处理两次请求

具体来看HandlerAdapter的处理过程

//根据HandlerMethod解析参数 并完成过程调用得到一个ModelAndView
private ModelAndView invokeHandleMethod(HttpServletRequest request,
                 HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  ServletWebRequest webRequest = new ServletWebRequest(request, response);
  try {
    //对@InitBinder的处理 主要是聚合了@InitBinder的所有处理方法
    WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    //@ModelAttribute的处理
    ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
    //对HandlerMethod的装饰,主要是增加了参数解析和返回值转化的功能
    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    //提供对参数解析的支持
    invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    //提供对返回值解析的支持
    invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    //提供对@InitBinder处理的支持
    invocableMethod.setDataBinderFactory(binderFactory);
    //TODO 尚不明功能
    invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    
    //可以看做handler()过程的上下文
    ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    modelFactory.initModel(webRequest, mavContainer, invocableMethod);
    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
==========================异步处理分割线=============    
    //AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务
    AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
    asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    //异步处理Manager
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    //设置异步执行线程池
    asyncManager.setTaskExecutor(this.taskExecutor);
    //提供对异步处理的支持
    asyncManager.setAsyncWebRequest(asyncWebRequest);
    //异步调用拦截器
    asyncManager.registerCallableInterceptors(this.callableInterceptors);
    asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
    //如果异步处理完成
    if (asyncManager.hasConcurrentResult()) {
      //获取异步执行结果
      Object result = asyncManager.getConcurrentResult();
      mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
      asyncManager.clearConcurrentResult();
      ...
      //替换invocableMethod(原先异步处理的方法返回值是Callable现在直接返回结果)
      invocableMethod = invocableMethod.wrapConcurrentResult(result);
    }
    //对invocableMethod进行参数解析,过程调用,返回值转化
    //并将结果存到mavContainer中
    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    //如果异步处理正在执行(已经开始,尚未结束) 立刻返回
    //同时DispatcherServlet也直接返回 等待AsyncContext.dispatch()调用再次进入doDispatch()方法
    if (asyncManager.isConcurrentHandlingStarted()) {
      return null;
    }
    //从mavContainer捞出结果
    return getModelAndView(mavContainer, modelFactory, webRequest);
  }
  finally {
    webRequest.requestCompleted();
  }
}

 

这里异步的处理 针对两次请求有两种处理

第一次请求: 开始异步请求

//AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
//异步处理Manager
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//设置异步执行线程池
asyncManager.setTaskExecutor(this.taskExecutor);
//提供对异步处理的支持
asyncManager.setAsyncWebRequest(asyncWebRequest);
//异步调用拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
//对invocableMethod进行参数解析,过程调用(调用AsyncWebRequest.startAsync()执行异步过程),返回值转化
//并将结果存到mavContainer中
invocableMethod.invokeAndHandle(webRequest, mavContainer);
//如果异步处理正在执行(已经开始,尚未结束) 立刻返回
//同时DispatcherServlet也直接返回 
return null;

#org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  ...
  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  if (asyncManager.isConcurrentHandlingStarted()) {
    return;
  }
  ...
}
//等待AsyncWebRequest.dispatch()被调用 然后再次进入doDispatch()方法

 

其实可以看到 在invokeHandleMethod()的处理过程除了最后直接返回null,前面的处理都和正常流程是一样的
在SpringMVC中异步方法无非只是返回值是个Callable()而已 ,所以其参数解析过程和正常流程是一样的,区别在于返回值解析过程
来看返回值处理过程

public class CallableMethodReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return Callable.class.isAssignableFrom(returnType.getParameterType());
    }
    @Override
    public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
        return (returnValue != null && returnValue instanceof Callable);
    }
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        if (returnValue == null) {
            mavContainer.setRequestHandled(true);
            return;
        }
        //将Callable对象丢给异步执行器执行
        Callable<?> callable = (Callable<?>) returnValue;
        WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
    }
}
#org.springframework.web.context.request.async.WebAsyncManager
public void startCallableProcessing(final WebAsyncTask<?> webAsyncTask, Object... processingContext) throws Exception {
    //超时控制,拦截器配置
    ...
    //调用Request.startAsync()得到AsyncContext对象
    startAsyncProcessing(processingContext);
    try {
        this.taskExecutor.submit(new Runnable() {
            @Override
            public void run() {
                Object result = null;
                try {
                    interceptorChain.applyPreProcess(asyncWebRequest, callable);
                    result = callable.call();
                }
                ...
                finally {
                    result = interceptorChain.applyPostProcess(asyncWebRequest, callable, result);
                }
                //通知异步执行结束 调用dispatch()
                setConcurrentResultAndDispatch(result);
            }
        });
    }
    catch (RejectedExecutionException ex) {
        //异常处理
        Object result = interceptorChain.applyPostProcess(this.asyncWebRequest, callable, ex);
        setConcurrentResultAndDispatch(result);
        throw ex;
    }
}
 private void setConcurrentResultAndDispatch(Object result) {
    ...
    //调用AsyncContext.dispatch() 通知servlet容器再起发起请求
    this.asyncWebRequest.dispatch();
}

 

第二次请求: 异步执行完成

 ```java
   //AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务
   AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
   asyncWebRequest.setTimeout(this.asyncRequestTimeout);
   //异步处理Manager
   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   //设置异步执行线程池
   asyncManager.setTaskExecutor(this.taskExecutor);
   //提供对异步处理的支持
   asyncManager.setAsyncWebRequest(asyncWebRequest);
   //异步调用拦截器
   asyncManager.registerCallableInterceptors(this.callableInterceptors);
   asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
   //异步处理完成 获取异步执行结果
   Object result = asyncManager.getConcurrentResult();
   mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
   asyncManager.clearConcurrentResult();
   //!!!替换invocableMethod(原先HandlerMethod中返回值是Callable现在直接返回结果,无需进行参数解析)
   invocableMethod = invocableMethod.wrapConcurrentResult(result);
   //对invocableMethod进行参数解析,过程调用,返回值转化
   //并将结果存到mavContainer中
   invocableMethod.invokeAndHandle(webRequest, mavContainer);
   //从mavContainer捞出结果
   return getModelAndView(mavContainer, modelFactory, webRequest);

 

以上就是直播带货源码,异步处理中会处理两次请求, 更多内容欢迎关注之后的文章

 

posted @ 2024-03-16 09:27  云豹科技-苏凌霄  阅读(4)  评论(0编辑  收藏  举报