直播帶貨原始碼,非同步處理中會處理兩次請求
從序列圖上可以看到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);
以上就是直播帶貨原始碼,非同步處理中會處理兩次請求, 更多內容歡迎關注之後的文章