首页 > 编程语言 >直播带货源码,异步处理中会处理两次请求

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

时间:2024-03-16 09:33:06浏览次数:21  
标签:异步 invocableMethod 处理 mavContainer 直播 asyncManager asyncWebRequest

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

在这里插入图片描述
从序列图上可以看到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);

 

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

 

标签:异步,invocableMethod,处理,mavContainer,直播,asyncManager,asyncWebRequest
From: https://www.cnblogs.com/yunbaomengnan/p/18076716

相关文章

  • 视频直播系统源码,异步处理实现代码分析
    视频直播系统源码,异步处理实现代码分析@OverrideprotectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{System.out.println("doget");method3(request,response);}/***使用asyncConte......
  • 后端返回的数据结构可能是多样的,前端需要对数据进行处理,以适应页面展示的需求。请给出
    在前端开发中,针对后端返回的多变数据结构进行处理以适应页面展示需求的最佳实践包括以下几个方面:定义清晰的数据模型:在前端根据UI设计和功能需求明确所需的数据结构,并创建对应的JavaScript对象模型(或使用TypeScript等类型语言提供静态类型检查)。这有助于前端开发者预先了解......
  • 后端返回的值,不能直接用于表单展示,有的表单项的值是根据其他表单项计算出来的,有的是根
    后端返回的值,不能直接用于表单展示,有的表单项的值是根据其他表单项计算出来的,有的是根据下拉框的选中项的其他属性获取到的,这时候该如何处理?还有最后要保存的时候,传给后端的值,与表单的数据结构也不一样,有的甚至没有放在表单属性上,比如当前下拉框选中的对象而非id,整个需要传给后端......
  • 数据预处理|数据清洗|使用Pandas进行异常值清洗
    数据预处理|数据清洗|使用Pandas进行异常值清洗使用Pandas进行异常值清洗1.异常值检测1.1简单统计分析1.2散点图方法1.33σ原则1.4箱线图2.异常值处理2.1直接删除2.2视为缺失值2.3平均值修正2.4盖帽法2.5分箱平滑法2.6回归插补2.7多重插补2.8不处理......
  • java 高效递归查询树 find_in_set 处理递归树
    建表语句DROPTABLEIFEXISTS`sys_dept`;CREATETABLE`sys_dept`(`id`bigint(20)NOTNULLAUTO_INCREMENTCOMMENT'部门id',`parent_id`bigint(20)DEFAULT'0'COMMENT'父部门id',`ancestors`varchar(256)DEFAULT''......
  • 微信小程序开发:异步处理接入的生成式图像卡通化
    书接上文,我们完成了对接阿里云人像动漫化接口,现已完成的界面是这样的: 就是效果看着一般,看看效果: 然后我就在阿里云api市场转悠,就想看看还有没有什么其他奇奇怪怪的api,结果就发现了这个:api链接这里:https://help.aliyun.com/zh/viapi/api-generative-image-cartoon ......
  • Python实战:Python异常处理机制及try-except-finally
    本文将详细介绍Python中的异常处理机制,以及如何使用try-except-finally语句来处理程序中的错误和异常情况。我们将深入探讨异常的概念、类型和层次结构,并展示如何在实际编程中应用异常处理来提高代码的健壮性和可维护性。1.引言在编程过程中,错误和异常是不可避免的。异常......
  • Django和Fastapi异步性能对比
    突发奇想,我想验证一下Python的异步后端框架的并发能力.目前主流的异步框架有Fastapi,Django和Tornado.顺便我想对比一下它们的性能,但是考虑到Tornado自成一派没有遵循Asgi,没办法屏蔽服务器部分的代码效率,所以我打算只拿Fastapi和Django做下对比.实验设计运行设备:4核8进......
  • 全量知识系统 因子分析+在线处理+实时库+生存拓扑控制+跨语言 的设想及百度AI答问 之3
    Q12.进一步,在因子分析+在线处理+生存拓扑控制的基础上,三种实时表的在线处理程序由三个不同程序语言的代理类来代理,以分离不同目标机的编程语言环境的影响。(因为,这里要限制目标编程语言中的数据类型以简化实现过程,并方便适应不同的应用需求).这三个代理类分别是:PythonBroker......
  • 图片水印处理
    publicstaticvoidmain(String[]args)throwsIOException{//读取图片文件信息Filefile=newFile("C:\Users\Administrator\Desktop\1.png");//将图片文件转为BufferedImage的对象BufferedImageimage=ImageIO.read(file);//注意:这里需要抛一个异常,要不然read()会报错......