SpringMVC流程源码分析及DispatcherServlet核心源码

一、源码分析前还是需要一张流程图作为指导,如下:


二、简单介绍以及源码定位

    DispatcherServlet其实就是一个HttpServlet,他是HttpServlet的子类,所以它和普通的HttpServlet在web.xml里同样的配置。

    这个Servlet的doPost和doGet方法的实现是DispatcherServlet的父类FrameworkServlet中实现的,两个方法里都是调用processRequest方法。processRequest的实现是在FrameworkServlet中,此方法中最主要的操作就是调用doService方法。

    doService方法的最终实现是在DispatcherServlet中,这样所有的Http请求(GET、POST、PUT和DELETE等)的最终操作就DispatcherServlet中实现了。

    DispatcherServlet中doService的实现如下,对Request设置了一些全局属性,最终接下来的操作是在doDispatcher函数中实现了。

[java] view plain copy
//获取请求,设置一些request的参数,然后分发给doDispatch  
    @Override  
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  
        if (logger.isDebugEnabled()) {  
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";  
            logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +  
                    " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");  
        }  
  
        // Keep a snapshot of the request attributes in case of an include,  
        // to be able to restore the original attributes after the include.  
        Map<String, Object> attributesSnapshot = null;  
        if (WebUtils.isIncludeRequest(request)) {  
            attributesSnapshot = new HashMap<String, Object>();  
            Enumeration<?> attrNames = request.getAttributeNames();  
            while (attrNames.hasMoreElements()) {  
                String attrName = (String) attrNames.nextElement();  
                if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {  
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));  
                }  
            }  
        }  
  
        // Make framework objects available to handlers and view objects.  
        /* 设置web应用上下文**/  
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());  
        /* 国际化本地**/  
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);  
        /* 样式**/  
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);  
        //设置样式资源  
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());  
        //请求刷新时保存属性  
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);  
        if (inputFlashMap != null) {  
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));  
        }  
        //Flash attributes 在对请求的重定向生效之前被临时存储(通常是在session)中,并且在重定向之后被立即移除  
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());  
        //FlashMap 被用来管理 flash attributes 而 FlashMapManager 则被用来存储,获取和管理 FlashMap 实体.  
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);  
  
        try {  
            doDispatch(request, response);  
        }  
        finally {  
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  
                // Restore the original attribute snapshot, in case of an include.  
                if (attributesSnapshot != null) {  
                    restoreAttributesAfterInclude(request, attributesSnapshot);  
                }  
            }  
        }  
    }  


doDispatch()方法源码如下:

/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	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.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				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.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
				}
			}
		}
	}

三、通过阅读源码总结分析流程如下:

1. web应用服务器接收到一个新请求是,读取web.xml中的配置,如果匹配DispatcherServlet的请求映射路径,web容器将该请求转发给DispatcherServlet进行处理 


2. DispatcherServlet接收到请求后,执行doDispatch方法,此方法遍历DispatcherServlet中的HandlerMapping(处理器映射器)集合,根据请求的HttpServletRequest信息通过HandlerMapping对象方法找到HandlerExecutionChain(执行链,内含拦截器和处理器)


3. DispatcherServlet继续执行doDispatch方法,根据得到的HandlerExecutionChain(执行链)中的handler遍历自己的HandlerAdapter(处理器适配器)集合,找到支持这个HandlerHandlerAdapter并返回。

 

4.继续doDispatch方法,把HandlerExecutionChain(执行链)内部的那些前置拦截器逻辑都执行完,然后再再通过得到的HandlerAdapter执行HandlerExecutionChain内部的处理器,会返回一个ModelAndView包含了视图逻辑名和模型数据信息 

 

5.调用执行链的方法,执行拦截器的后置拦截器


6. ModelAndView中包含的是逻辑视图名,而非真正的视图对象,DispatcherServlet借助ViewResolver完成逻辑视图名到真实视图名对象的解析工作 


7. 当得到真实的视图对象View后,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染 


8. 最终客户端得到HTML页面什么的


原文地址:https://www.cnblogs.com/chz-blogs/p/9380919.html