springMVC源码执行流程

SpringMVC处理请求的流程即为

  1. 调⽤getHandler()获取到能够处理当前请求的执⾏链 HandlerExecutionChain(Handler+拦截 器)
  2. 调⽤getHandlerAdapter();获取能够执⾏1)中Handler的适配器
  3. 适配器调⽤Handler执⾏ha.handle(总会返回⼀个ModelAndView对象)
  4. 调⽤processDispatchResult()⽅法完成视图渲染跳转

doDispathch:

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 {
			// 1 检查是否是⽂件上传的请求
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);
			// Determine handler for the current request.
			/*
 			 *2 取得处理当前请求的Controller,这⾥也称为Handler,即处理器
 			 *这⾥并不是直接返回 Controller,⽽是返回 HandlerExecutionChain 请求处理链对象该对象封装了Handler和Inteceptor
			 */
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				// 如果 handler 为空,则返回404
				noHandlerFound(processedRequest, response);
				return;
			}
			// Determine handler adapter for the current request.
			// 3 获取处理请求的处理器适配器 HandlerAdapter
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
			// Process last-modified header, if supported by the handler.
			// 处理 last-modified 请求头
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request,
						mappedHandler.getHandler());
				if (new ServletWebRequest(request,
						response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}
			// Actually invoke the handler.
			// 4 实际处理器处理请求,返回结果视图对象
			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);
		}
		// 5 跳转⻚⾯,渲染视图
		processDispatchResult(processedRequest, response, mappedHandler, mv,
				dispatchException);
	}
	catch (Exception ex) {
		//最终会调⽤HandlerInterceptor的afterCompletion ⽅法
		triggerAfterCompletion(processedRequest, response, mappedHandler,
				ex);
	}
	catch (Throwable err) {
		//最终会调⽤HandlerInterceptor的afterCompletion ⽅法
		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

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				if (logger.isTraceEnabled()) {
					logger.trace(
							"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
				}
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

遍历HandlerMapping,试图获取能够处理当前请求的执⾏链

getHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter ha : this.handlerAdapters) {
				if (logger.isTraceEnabled()) {
					logger.trace("Testing handler adapter [" + ha + "]");
				}
				if (ha.supports(handler)) {
					return ha;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

ha.handle
在这里插入图片描述
processDispatchResult

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
		if (mv != null && !mv.wasCleared()) {
			//完成渲染
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
						"': assuming HandlerAdapter completed request handling");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

render()完成渲染

在这里插入图片描述
视图解析器解析出View视图对象

在这里插入图片描述
在解析出View视图对象的过程中会判断是否重定向、是否转发等,不同的情况封装的是不同的
View实现

在这里插入图片描述
解析出View视图对象的过程中,要将逻辑视图名解析为物理视图名

在这里插入图片描述
封装View视图对象之后,调⽤了view对象的render⽅法

在这里插入图片描述
渲染数据

在这里插入图片描述
把modelMap中的数据暴露到request域中,这也是为什么后台model.add之后在jsp中可以从请求
域取出来的根本原因

在这里插入图片描述
将数据设置到请求域中

猜你喜欢

转载自blog.csdn.net/qq_23830637/article/details/104037285