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 attributesSnapshot = null;  
        if (WebUtils.isIncludeRequest(request)) {  
            attributesSnapshot = new HashMap();  
            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.
	 * 

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. *

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页面什么的


你可能感兴趣的:(SpringMVC流程源码分析及DispatcherServlet核心源码)