springMVC源码分析--DispatcherServlet请求获取及处理

来源:互联网 发布:淘宝海选报名技巧 编辑:程序博客网 时间:2024/06/02 20:23

在之前的博客 springMVC源码分析--容器初始化(二)DispatcherServlet中我们介绍过DispatcherServlet,是在容器初始化过程中出现的,我们之前也说过DispatcherServlet其实就是一个HttpServlet,其实他是HttpServlet的子类,所以它和普通的HttpServlet有同样的配置:

[html] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;"><span style="white-space:pre">    </span><servlet>  
  2.         <servlet-name>springmvc</servlet-name>  
  3.         <servlet-class>  
  4.             org.springframework.web.servlet.DispatcherServlet  
  5.         </servlet-class>  
  6.         <init-param>  
  7.             <param-name>contextConfigLocation</param-name>  
  8.             <param-value>classpath:springmvc-config.xml</param-value>  
  9.         </init-param>  
  10.         <load-on-startup>1</load-on-startup>      
  11.     </servlet>  
  12.   
  13.     <servlet-mapping>  
  14.         <servlet-name>springmvc</servlet-name>  
  15.         <url-pattern>*.action</url-pattern>  
  16.     </servlet-mapping></span>  
仅仅把DispatcherServlet当做一个Servlet的话,上面配置的含义就是这个Servlet会被所有的*.action的请求所调用。

既然DispatcherServlet是一个HttpServlet那么它应该会实现HttpServlet提供的如下方法:


当然这些所有的方法的实现是DispatcherServlet的父类FrameworkServlet中实现的。


当然这些实现方法中的默认实现其实是如下的

FrameworkServlet类中

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     protected final void doPost(HttpServletRequest request, HttpServletResponse response)  
  3.             throws ServletException, IOException {  
  4.   
  5.         processRequest(request, response);  
  6.     }  
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2.     protected final void doGet(HttpServletRequest request, HttpServletResponse response)  
  3.             throws ServletException, IOException {  
  4.   
  5.         processRequest(request, response);  
  6.     }  
processRequest的实现是在FrameworkServlet中,此方法中最主要的操作就是调用doService方法
[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. protected final void processRequest(HttpServletRequest request, HttpServletResponse response)  
  2.             throws ServletException, IOException {  
  3.   
  4.         long startTime = System.currentTimeMillis();  
  5.         Throwable failureCause = null;  
  6.   
  7.         LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();  
  8.         LocaleContext localeContext = buildLocaleContext(request);  
  9.   
  10.         RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();  
  11.         ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);  
  12.   
  13.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  14.         asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());  
  15.   
  16.         initContextHolders(request, localeContext, requestAttributes);  
  17.   
  18.         try {  
  19.             doService(request, response);  
  20.         }  
  21.         catch (ServletException ex) {  
  22.             failureCause = ex;  
  23.             throw ex;  
  24.         }  
  25.         catch (IOException ex) {  
  26.             failureCause = ex;  
  27.             throw ex;  
  28.         }  
  29.         catch (Throwable ex) {  
  30.             failureCause = ex;  
  31.             throw new NestedServletException("Request processing failed", ex);  
  32.         }  
  33.   
  34.         finally {  
  35.             resetContextHolders(request, previousLocaleContext, previousAttributes);  
  36.             if (requestAttributes != null) {  
  37.                 requestAttributes.requestCompleted();  
  38.             }  
  39.   
  40.             if (logger.isDebugEnabled()) {  
  41.                 if (failureCause != null) {  
  42.                     this.logger.debug("Could not complete request", failureCause);  
  43.                 }  
  44.                 else {  
  45.                     if (asyncManager.isConcurrentHandlingStarted()) {  
  46.                         logger.debug("Leaving response open for concurrent processing");  
  47.                     }  
  48.                     else {  
  49.                         this.logger.debug("Successfully completed request");  
  50.                     }  
  51.                 }  
  52.             }  
  53.   
  54.             publishRequestHandledEvent(request, response, startTime, failureCause);  
  55.         }  
  56.     }  

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

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

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. //获取请求,设置一些request的参数,然后分发给doDispatch  
  2.     @Override  
  3.     protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  4.         if (logger.isDebugEnabled()) {  
  5.             String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";  
  6.             logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +  
  7.                     " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");  
  8.         }  
  9.   
  10.         // Keep a snapshot of the request attributes in case of an include,  
  11.         // to be able to restore the original attributes after the include.  
  12.         Map<String, Object> attributesSnapshot = null;  
  13.         if (WebUtils.isIncludeRequest(request)) {  
  14.             attributesSnapshot = new HashMap<String, Object>();  
  15.             Enumeration<?> attrNames = request.getAttributeNames();  
  16.             while (attrNames.hasMoreElements()) {  
  17.                 String attrName = (String) attrNames.nextElement();  
  18.                 if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {  
  19.                     attributesSnapshot.put(attrName, request.getAttribute(attrName));  
  20.                 }  
  21.             }  
  22.         }  
  23.   
  24.         // Make framework objects available to handlers and view objects.  
  25.         /* 设置web应用上下文**/  
  26.         request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());  
  27.         /* 国际化本地**/  
  28.         request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);  
  29.         /* 样式**/  
  30.         request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);  
  31.         //设置样式资源  
  32.         request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());  
  33.         //请求刷新时保存属性  
  34.         FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);  
  35.         if (inputFlashMap != null) {  
  36.             request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));  
  37.         }  
  38.         //Flash attributes 在对请求的重定向生效之前被临时存储(通常是在session)中,并且在重定向之后被立即移除  
  39.         request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());  
  40.         //FlashMap 被用来管理 flash attributes 而 FlashMapManager 则被用来存储,获取和管理 FlashMap 实体.  
  41.         request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);  
  42.   
  43.         try {  
  44.             doDispatch(request, response);  
  45.         }  
  46.         finally {  
  47.             if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  
  48.                 // Restore the original attribute snapshot, in case of an include.  
  49.                 if (attributesSnapshot != null) {  
  50.                     restoreAttributesAfterInclude(request, attributesSnapshot);  
  51.                 }  
  52.             }  
  53.         }  
  54.     }  
doDispatch函数中完成了对一个请求的所有操作,包含的内容还是比较多的,我们就不做详细分解,接下来我们会一步一步的分析一个请求调用Controller的完整过程。

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.      *将Handler进行分发,handler会被handlerMapping有序的获得 
  3.      *通过查询servlet安装的HandlerAdapters来获得HandlerAdapters来查找第一个支持handler的类 
  4.      *所有的HTTP的方法都会被这个方法掌控。取决于HandlerAdapters 或者handlers 他们自己去决定哪些方法是可用 
  5.      *@param request current HTTP request 
  6.      *@param response current HTTP response 
  7.      */  
  8.     protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  9.         /* 当前HTTP请求**/  
  10.         HttpServletRequest processedRequest = request;  
  11.         HandlerExecutionChain mappedHandler = null;  
  12.         boolean multipartRequestParsed = false;  
  13.   
  14.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  15.   
  16.         try {  
  17.             ModelAndView mv = null;  
  18.             Exception dispatchException = null;  
  19.   
  20.             try {  
  21.                 //判断是否有文件上传  
  22.                 processedRequest = checkMultipart(request);  
  23.                 multipartRequestParsed = (processedRequest != request);  
  24.   
  25.                 // 获得HandlerExecutionChain,其包含HandlerIntercrptor和HandlerMethod  
  26.                 mappedHandler = getHandler(processedRequest);  
  27.                 if (mappedHandler == null || mappedHandler.getHandler() == null) {  
  28.                     noHandlerFound(processedRequest, response);  
  29.                     return;  
  30.                 }  
  31.   
  32.                   
  33.                 //获得HandlerAdapter  
  34.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  35.   
  36.                 //获得HTTP请求方法  
  37.                 String method = request.getMethod();  
  38.                 boolean isGet = "GET".equals(method);  
  39.                 if (isGet || "HEAD".equals(method)) {  
  40.                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
  41.                     if (logger.isDebugEnabled()) {  
  42.                         logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);  
  43.                     }  
  44.                     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
  45.                         return;  
  46.                     }  
  47.                 }  
  48.                 //如果有拦截器的话,会执行拦截器的preHandler方法  
  49.                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
  50.                     return;  
  51.                 }  
  52.   
  53.                 //返回ModelAndView  
  54.                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  55.   
  56.                 if (asyncManager.isConcurrentHandlingStarted()) {  
  57.                     return;  
  58.                 }  
  59.                 //当view为空时,,根据request设置默认view  
  60.                 applyDefaultViewName(processedRequest, mv);  
  61.                 //执行拦截器的postHandle  
  62.                 mappedHandler.applyPostHandle(processedRequest, response, mv);  
  63.             }  
  64.             catch (Exception ex) {  
  65.                 dispatchException = ex;  
  66.             }  
  67.             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
  68.         }  
  69.         catch (Exception ex) {  
  70.             triggerAfterCompletion(processedRequest, response, mappedHandler, ex);  
  71.         }  
  72.         catch (Error err) {  
  73.             triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);  
  74.         }  
  75.         finally {  
  76.             //判断是否是异步请求  
  77.             if (asyncManager.isConcurrentHandlingStarted()) {  
  78.                 // Instead of postHandle and afterCompletion  
  79.                 if (mappedHandler != null) {  
  80.                     mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
  81.                 }  
  82.             }  
  83.             else {  
  84.                 // Clean up any resources used by a multipart request.  
  85.                 //删除上传资源  
  86.                 if (multipartRequestParsed) {  
  87.                     cleanupMultipart(processedRequest);  
  88.                 }  
  89.             }  
  90.         }  
  91.     }  
调用完doDispatch之后就完成了一个请求的访问,其会将渲染后的页面或者数据返回给请求发起者。
0 0