直播带货源码,异步处理中会处理两次请求
从序列图上可以看到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