【十六】Spring源碼分析之MVC------DispatcherServlet類的doDispatch(一次請求中SpringMVC主要做些什麼事)

一次請求中SpringMVC主要做些什麼事

   getHandler,                     HandlerMapping通過URL查找handler
   getHandlerAdapter,               通過handler查找匹配的HandlerAdapter
   mappedHandler.applyPreHandle,    調用前置攔截
   ha.handle,                       HandlerAdapter調用handler
   mappedHandler.applyPostHandle,   調用後置攔截
   processDispatchResult,           渲染視圖

而這些流程的最外層在dispatcherServlet類的源碼中有體現:

DispatcherServlet類的doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
 
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
 
            try {


                ////檢查是否存在文件上傳
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
 
                // Determine handler for the current request.
 
                //得到是哪個handler處理,即是哪個controller處理這個請求
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
 
                // Determine handler adapter for the current request.
                //得到handler適配器
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 
                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
 
                //前置處理
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
 
                // Actually invoke the handler.
                //通過適配器調用真的的controller的方法
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
 
                applyDefaultViewName(processedRequest, mv);
 
                //後置處理
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                // As of 4.3, we're processing Errors thrown from handler methods as well,
                // making them available for @ExceptionHandler methods and other scenarios.
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
 
            //渲染視圖
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }


 其中getHandler只是知道用哪個controller的哪個方法,ha.handle裏面纔是重點,調用了實際的處理方法和綁定入參,實際上這裏的ha.handle是調用的RequestMappingHandlerAdapter類的handleInternal方法

RequestMappingHandlerAdapter類的invokeHandlerMethod

方法源碼如下:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

           //使用裝飾模式對HandlerMethod進行增強,ServletInvocableHandlerMethod實際上是HandlerMethod的子類
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);

           //設置參數解析器,用於參數解析。
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			

          //設置返回值解析器,用於解析不同的返回值(比如返回View或者Responsebody)
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);

			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();
				if (logger.isDebugEnabled()) {
					logger.debug("Found concurrent result value [" + result + "]");
				}
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}

            //執行調用方法
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

            //返回ModelAndView對象
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

做了幾件事:

1.使用裝飾模式對HandlerMethod進行增強,ServletInvocableHandlerMethod實際上是HandlerMethod的子類

2.設置參數解析器,用於參數解析。

3.設置返回值解析器,用於解析不同的返回值(比如返回View或者Responsebody)

4.執行調用方法

5.返回ModelAndView對象

 跟到invocableMethod.invokeAndHandle(webRequest, mavContainer);方法中

InvocableHandlerMethod類.invokeForRequest的源碼

	public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

        //綁定參數,得到調用方法需要的入參
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
					"' with arguments " + Arrays.toString(args));
		}

       //調用實際的controller的方法
		Object returnValue = doInvoke(args);
		if (logger.isTraceEnabled()) {
			logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
					"] returned [" + returnValue + "]");
		}
		return returnValue;
	}

做了兩件事:

1.getMethodArgumentValues  綁定參數,得到需要調用的方法的入參

2.doInvoke用反射調用實際的方法

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章