《spring mvc》1 源碼分析

1 根據url獲取HandlerExecutionChain

從debug的堆棧圖中可以看到HandlerExecutionChain的結構:

(1)url對應的controller bean

(2)url對應的method

(3)所有該請求url攔截規則的intercepter

2 獲取處理器

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

3 遍歷攔截器並調用攔截器的preHandle

// Apply preHandle methods of registered interceptors.
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
	for (int i = 0; i < interceptors.length; i++) {
		HandlerInterceptor interceptor = interceptors[i];
		if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler()))           {
		    triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
			return;
		}
		interceptorIndex = i;
	}
}

4 利用java 反射調用controller的實際方法,其中數據綁定部分的代碼,在controller中可使用@InitBinder

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// RequestMappingHandlerAdapter
protected final ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ...
    return invokeHandleMethod(request, response, handlerMethod);
    ...
}

private ModelAndView invokeHandleMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ...
    // 在controller中用@InitBinder就是在這裏面起作用,比如對String類型進行html編碼
    WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    ...
    requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
    ...
}

// InvocableHandlerMethod
private Object invoke(Object... args) throws Exception{
ReflectionUtils.makeAccessible(getBridgedMethod());
...
    return getBridgedMethod().invoke(getBean(), args);
...
}

5 調用攔截器的postHandle方法

 mappedHandler.applyPostHandle(processedRequest, response, mv);

6 處理異常和結果,在controller中可以定義@ExceptionHandler({BindException.class,WebException.class, ConstraintViolationException.class, ValidationException.class})註解進行異常處理。

(1)異常處理

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);


private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception){
    ...
     mv = processHandlerException(request, response, handler, exception);    
    ...
}

(2)返回結果處理,最後調用的是javax包的forward、include、sendRedirect等等方法

@Override
	public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isTraceEnabled()) {
			logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
				" and static attributes " + this.staticAttributes);
		}

		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		prepareResponse(request, response);
		renderMergedOutputModel(mergedModel, request, response);
	}

// 最後調用的是javax包的forward、include等等方法
@Override
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// Determine which request handle to expose to the RequestDispatcher.
		HttpServletRequest requestToExpose = getRequestToExpose(request);

		// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, requestToExpose);

		// Expose helpers as request attributes, if any.
		exposeHelpers(requestToExpose);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(requestToExpose, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		if (useInclude(requestToExpose, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(requestToExpose, response);
		}

		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.forward(requestToExpose, response);
		}
	}

7 在finally塊中執行攔截器的applyAfterConcurrentHandlingStarted方法

if (asyncManager.isConcurrentHandlingStarted()){
    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    return;
}

 

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