zoukankan      html  css  js  c++  java
  • DispatcherServlet源码注解分析

    DispatcherServlet的介绍与工作流程

            DispatcherServlet是SpringMVC的前端分发控制器,用于处理客户端请求,然后交给对应的handler进行处理,返回对应的模型和视图,视图解析器根据视图名称进行视图渲染,然后返回给DispatcherServlet,该分发servlet将渲染好的视图页面呈现给用户。

    工作流程图

    下面是对DispatcherServlet的源码注解分析,后期将会不断完善

       1 /*
       2  * Copyright 2002-2017 the original author or authors.
       3  *
       4  * Licensed under the Apache License, Version 2.0 (the "License");
       5  * you may not use this file except in compliance with the License.
       6  * You may obtain a copy of the License at
       7  *
       8  *      http://www.apache.org/licenses/LICENSE-2.0
       9  *
      10  * Unless required by applicable law or agreed to in writing, software
      11  * distributed under the License is distributed on an "AS IS" BASIS,
      12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13  * See the License for the specific language governing permissions and
      14  * limitations under the License.
      15  */
      16 
      17 package org.springframework.web.servlet;
      18 
      19 import java.io.IOException;
      20 import java.util.ArrayList;
      21 import java.util.Collections;
      22 import java.util.Enumeration;
      23 import java.util.HashMap;
      24 import java.util.HashSet;
      25 import java.util.LinkedList;
      26 import java.util.List;
      27 import java.util.Locale;
      28 import java.util.Map;
      29 import java.util.Properties;
      30 import java.util.Set;
      31 import javax.servlet.ServletContext;
      32 import javax.servlet.ServletException;
      33 import javax.servlet.http.HttpServletRequest;
      34 import javax.servlet.http.HttpServletResponse;
      35 
      36 import org.apache.commons.logging.Log;
      37 import org.apache.commons.logging.LogFactory;
      38 
      39 import org.springframework.beans.factory.BeanFactoryUtils;
      40 import org.springframework.beans.factory.BeanInitializationException;
      41 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
      42 import org.springframework.context.ApplicationContext;
      43 import org.springframework.context.ConfigurableApplicationContext;
      44 import org.springframework.context.i18n.LocaleContext;
      45 import org.springframework.core.annotation.AnnotationAwareOrderComparator;
      46 import org.springframework.core.io.ClassPathResource;
      47 import org.springframework.core.io.support.PropertiesLoaderUtils;
      48 import org.springframework.http.server.ServletServerHttpRequest;
      49 import org.springframework.ui.context.ThemeSource;
      50 import org.springframework.util.ClassUtils;
      51 import org.springframework.util.StringUtils;
      52 import org.springframework.web.context.WebApplicationContext;
      53 import org.springframework.web.context.request.ServletWebRequest;
      54 import org.springframework.web.context.request.async.WebAsyncManager;
      55 import org.springframework.web.context.request.async.WebAsyncUtils;
      56 import org.springframework.web.multipart.MultipartException;
      57 import org.springframework.web.multipart.MultipartHttpServletRequest;
      58 import org.springframework.web.multipart.MultipartResolver;
      59 import org.springframework.web.util.NestedServletException;
      60 import org.springframework.web.util.WebUtils;
      61 
      62 /**
      63  * Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers
      64  * or HTTP-based remote service exporters. Dispatches to registered handlers for processing
      65  * a web request, providing convenient mapping and exception handling facilities.
      66  *
      67  * <p>This servlet is very flexible: It can be used with just about any workflow, with the
      68  * installation of the appropriate adapter classes. It offers the following functionality
      69  * that distinguishes it from other request-driven web MVC frameworks:
      70  *
      71  * <ul>
      72  * <li>It is based around a JavaBeans configuration mechanism.
      73  *
      74  * <li>It can use any {@link HandlerMapping} implementation - pre-built or provided as part
      75  * of an application - to control the routing of requests to handler objects. Default is
      76  * {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping} and
      77  * {@link org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping}.
      78  * HandlerMapping objects can be defined as beans in the servlet's application context,
      79  * implementing the HandlerMapping interface, overriding the default HandlerMapping if
      80  * present. HandlerMappings can be given any bean name (they are tested by type).
      81  *
      82  * <li>It can use any {@link HandlerAdapter}; this allows for using any handler interface.
      83  * Default adapters are {@link org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter},
      84  * {@link org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter}, for Spring's
      85  * {@link org.springframework.web.HttpRequestHandler} and
      86  * {@link org.springframework.web.servlet.mvc.Controller} interfaces, respectively. A default
      87  * {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
      88  * will be registered as well. HandlerAdapter objects can be added as beans in the
      89  * application context, overriding the default HandlerAdapters. Like HandlerMappings,
      90  * HandlerAdapters can be given any bean name (they are tested by type).
      91  *
      92  * <li>The dispatcher's exception resolution strategy can be specified via a
      93  * {@link HandlerExceptionResolver}, for example mapping certain exceptions to error pages.
      94  * Default are
      95  * {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver},
      96  * {@link org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver}, and
      97  * {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver}.
      98  * These HandlerExceptionResolvers can be overridden through the application context.
      99  * HandlerExceptionResolver can be given any bean name (they are tested by type).
     100  *
     101  * <li>Its view resolution strategy can be specified via a {@link ViewResolver}
     102  * implementation, resolving symbolic view names into View objects. Default is
     103  * {@link org.springframework.web.servlet.view.InternalResourceViewResolver}.
     104  * ViewResolver objects can be added as beans in the application context, overriding the
     105  * default ViewResolver. ViewResolvers can be given any bean name (they are tested by type).
     106  *
     107  * <li>If a {@link View} or view name is not supplied by the user, then the configured
     108  * {@link RequestToViewNameTranslator} will translate the current request into a view name.
     109  * The corresponding bean name is "viewNameTranslator"; the default is
     110  * {@link org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator}.
     111  *
     112  * <li>The dispatcher's strategy for resolving multipart requests is determined by a
     113  * {@link org.springframework.web.multipart.MultipartResolver} implementation.
     114  * Implementations for Apache Commons FileUpload and Servlet 3 are included; the typical
     115  * choice is {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}.
     116  * The MultipartResolver bean name is "multipartResolver"; default is none.
     117  *
     118  * <li>Its locale resolution strategy is determined by a {@link LocaleResolver}.
     119  * Out-of-the-box implementations work via HTTP accept header, cookie, or session.
     120  * The LocaleResolver bean name is "localeResolver"; default is
     121  * {@link org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}.
     122  *
     123  * <li>Its theme resolution strategy is determined by a {@link ThemeResolver}.
     124  * Implementations for a fixed theme and for cookie and session storage are included.
     125  * The ThemeResolver bean name is "themeResolver"; default is
     126  * {@link org.springframework.web.servlet.theme.FixedThemeResolver}.
     127  * </ul>
     128  *
     129  * <p><b>NOTE: The {@code @RequestMapping} annotation will only be processed if a
     130  * corresponding {@code HandlerMapping} (for type-level annotations) and/or
     131  * {@code HandlerAdapter} (for method-level annotations) is present in the dispatcher.</b>
     132  * This is the case by default. However, if you are defining custom {@code HandlerMappings}
     133  * or {@code HandlerAdapters}, then you need to make sure that a corresponding custom
     134  * {@code DefaultAnnotationHandlerMapping} and/or {@code AnnotationMethodHandlerAdapter}
     135  * is defined as well - provided that you intend to use {@code @RequestMapping}.
     136  *
     137  * <p><b>A web application can define any number of DispatcherServlets.</b>
     138  * Each servlet will operate in its own namespace, loading its own application context
     139  * with mappings, handlers, etc. Only the root application context as loaded by
     140  * {@link org.springframework.web.context.ContextLoaderListener}, if any, will be shared.
     141  *
     142  * <p>As of Spring 3.1, {@code DispatcherServlet} may now be injected with a web
     143  * application context, rather than creating its own internally. This is useful in Servlet
     144  * 3.0+ environments, which support programmatic registration of servlet instances.
     145  * See the {@link #DispatcherServlet(WebApplicationContext)} javadoc for details.
     146  *
     147  * @author Rod Johnson
     148  * @author Juergen Hoeller
     149  * @author Rob Harrop
     150  * @author Chris Beams
     151  * @author Rossen Stoyanchev
     152  * @see org.springframework.web.HttpRequestHandler
     153  * @see org.springframework.web.servlet.mvc.Controller
     154  * @see org.springframework.web.context.ContextLoaderListener
     155  */
     156 @SuppressWarnings("serial")
     157 public class DispatcherServlet extends FrameworkServlet {
     158 
     159     /** Well-known name for the MultipartResolver object in the bean factory for this namespace. */
     160     public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
     161 
     162     /** Well-known name for the LocaleResolver object in the bean factory for this namespace. */
     163     public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
     164 
     165     /** Well-known name for the ThemeResolver object in the bean factory for this namespace. */
     166     public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
     167 
     168     /**
     169      * Well-known name for the HandlerMapping object in the bean factory for this namespace.
     170      * Only used when "detectAllHandlerMappings" is turned off.
     171      * @see #setDetectAllHandlerMappings
     172      */
     173     public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
     174 
     175     /**
     176      * Well-known name for the HandlerAdapter object in the bean factory for this namespace.
     177      * Only used when "detectAllHandlerAdapters" is turned off.
     178      * @see #setDetectAllHandlerAdapters
     179      */
     180     public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
     181 
     182     /**
     183      * Well-known name for the HandlerExceptionResolver object in the bean factory for this namespace.
     184      * Only used when "detectAllHandlerExceptionResolvers" is turned off.
     185      * @see #setDetectAllHandlerExceptionResolvers
     186      */
     187     public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
     188 
     189     /**
     190      * Well-known name for the RequestToViewNameTranslator object in the bean factory for this namespace.
     191      */
     192     public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
     193 
     194     /**
     195      * Well-known name for the ViewResolver object in the bean factory for this namespace.
     196      * Only used when "detectAllViewResolvers" is turned off.
     197      * @see #setDetectAllViewResolvers
     198      */
     199     public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
     200 
     201     /**
     202      * Well-known name for the FlashMapManager object in the bean factory for this namespace.
     203      */
     204     public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
     205 
     206     /**
     207      * Request attribute to hold the current web application context.
     208      * Otherwise only the global web app context is obtainable by tags etc.
     209      * @see org.springframework.web.servlet.support.RequestContextUtils#findWebApplicationContext
     210      */
     211     public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
     212 
     213     /**
     214      * Request attribute to hold the current LocaleResolver, retrievable by views.
     215      * @see org.springframework.web.servlet.support.RequestContextUtils#getLocaleResolver
     216      */
     217     public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
     218 
     219     /**
     220      * Request attribute to hold the current ThemeResolver, retrievable by views.
     221      * @see org.springframework.web.servlet.support.RequestContextUtils#getThemeResolver
     222      */
     223     public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
     224 
     225     /**
     226      * Request attribute to hold the current ThemeSource, retrievable by views.
     227      * @see org.springframework.web.servlet.support.RequestContextUtils#getThemeSource
     228      */
     229     public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
     230 
     231     /**
     232      * Name of request attribute that holds a read-only {@code Map<String,?>}
     233      * with "input" flash attributes saved by a previous request, if any.
     234      * @see org.springframework.web.servlet.support.RequestContextUtils#getInputFlashMap(HttpServletRequest)
     235      */
     236     public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";
     237 
     238     /**
     239      * Name of request attribute that holds the "output" {@link FlashMap} with
     240      * attributes to save for a subsequent request.
     241      * @see org.springframework.web.servlet.support.RequestContextUtils#getOutputFlashMap(HttpServletRequest)
     242      */
     243     public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";
     244 
     245     /**
     246      * Name of request attribute that holds the {@link FlashMapManager}.
     247      * @see org.springframework.web.servlet.support.RequestContextUtils#getFlashMapManager(HttpServletRequest)
     248      */
     249     public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";
     250 
     251     /**
     252      * Name of request attribute that exposes an Exception resolved with an
     253      * {@link HandlerExceptionResolver} but where no view was rendered
     254      * (e.g. setting the status code).
     255      */
     256     public static final String EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() + ".EXCEPTION";
     257 
     258     /** Log category to use when no mapped handler is found for a request. */
     259     public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
     260 
     261     /**
     262      * Name of the class path resource (relative to the DispatcherServlet class)
     263      * that defines DispatcherServlet's default strategy names.
     264      */
     265     private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
     266 
     267     /**
     268      * Common prefix that DispatcherServlet's default strategy attributes start with.
     269      */
     270     private static final String DEFAULT_STRATEGIES_PREFIX = "org.springframework.web.servlet";
     271 
     272     /** Additional logger to use when no mapped handler is found for a request. */
     273     protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
     274 
     275     private static final Properties defaultStrategies;
     276 
     277     static {
     278         // Load default strategy implementations from properties file.
     279         // This is currently strictly internal and not meant to be customized
     280         // by application developers.
     281         try {
     282             ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
     283             defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
     284         }
     285         catch (IOException ex) {
     286             throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
     287         }
     288     }
     289 
     290     /** Detect all HandlerMappings or just expect "handlerMapping" bean? */
     291     private boolean detectAllHandlerMappings = true;
     292 
     293     /** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
     294     private boolean detectAllHandlerAdapters = true;
     295 
     296     /** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
     297     private boolean detectAllHandlerExceptionResolvers = true;
     298 
     299     /** Detect all ViewResolvers or just expect "viewResolver" bean? */
     300     private boolean detectAllViewResolvers = true;
     301 
     302     /** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
     303     private boolean throwExceptionIfNoHandlerFound = false;
     304 
     305     /** Perform cleanup of request attributes after include request? */
     306     private boolean cleanupAfterInclude = true;
     307 
     308     /** MultipartResolver used by this servlet */
     309     private MultipartResolver multipartResolver;
     310 
     311     /** LocaleResolver used by this servlet */
     312     private LocaleResolver localeResolver;
     313 
     314     /** ThemeResolver used by this servlet */
     315     private ThemeResolver themeResolver;
     316 
     317     /** List of HandlerMappings used by this servlet */
     318     private List<HandlerMapping> handlerMappings;
     319 
     320     /** List of HandlerAdapters used by this servlet */
     321     private List<HandlerAdapter> handlerAdapters;
     322 
     323     /** List of HandlerExceptionResolvers used by this servlet */
     324     private List<HandlerExceptionResolver> handlerExceptionResolvers;
     325 
     326     /** RequestToViewNameTranslator used by this servlet */
     327     private RequestToViewNameTranslator viewNameTranslator;
     328 
     329     /** FlashMapManager used by this servlet */
     330     private FlashMapManager flashMapManager;
     331 
     332     /** List of ViewResolvers used by this servlet */
     333     private List<ViewResolver> viewResolvers;
     334 
     335 
     336     /**
     337      * Create a new {@code DispatcherServlet} that will create its own internal web
     338      * application context based on defaults and values provided through servlet
     339      * init-params. Typically used in Servlet 2.5 or earlier environments, where the only
     340      * option for servlet registration is through {@code web.xml} which requires the use
     341      * of a no-arg constructor.
     342      * <p>Calling {@link #setContextConfigLocation} (init-param 'contextConfigLocation')
     343      * will dictate which XML files will be loaded by the
     344      * {@linkplain #DEFAULT_CONTEXT_CLASS default XmlWebApplicationContext}
     345      * <p>Calling {@link #setContextClass} (init-param 'contextClass') overrides the
     346      * default {@code XmlWebApplicationContext} and allows for specifying an alternative class,
     347      * such as {@code AnnotationConfigWebApplicationContext}.
     348      * <p>Calling {@link #setContextInitializerClasses} (init-param 'contextInitializerClasses')
     349      * indicates which {@code ApplicationContextInitializer} classes should be used to
     350      * further configure the internal application context prior to refresh().
     351      * @see #DispatcherServlet(WebApplicationContext)
     352      */
     353     public DispatcherServlet() {
     354         super();
     355         setDispatchOptionsRequest(true);
     356     }
     357 
     358     /**
     359      * Create a new {@code DispatcherServlet} with the given web application context. This
     360      * constructor is useful in Servlet 3.0+ environments where instance-based registration
     361      * of servlets is possible through the {@link ServletContext#addServlet} API.
     362      * <p>Using this constructor indicates that the following properties / init-params
     363      * will be ignored:
     364      * <ul>
     365      * <li>{@link #setContextClass(Class)} / 'contextClass'</li>
     366      * <li>{@link #setContextConfigLocation(String)} / 'contextConfigLocation'</li>
     367      * <li>{@link #setContextAttribute(String)} / 'contextAttribute'</li>
     368      * <li>{@link #setNamespace(String)} / 'namespace'</li>
     369      * </ul>
     370      * <p>The given web application context may or may not yet be {@linkplain
     371      * ConfigurableApplicationContext#refresh() refreshed}. If it has <strong>not</strong>
     372      * already been refreshed (the recommended approach), then the following will occur:
     373      * <ul>
     374      * <li>If the given context does not already have a {@linkplain
     375      * ConfigurableApplicationContext#setParent parent}, the root application context
     376      * will be set as the parent.</li>
     377      * <li>If the given context has not already been assigned an {@linkplain
     378      * ConfigurableApplicationContext#setId id}, one will be assigned to it</li>
     379      * <li>{@code ServletContext} and {@code ServletConfig} objects will be delegated to
     380      * the application context</li>
     381      * <li>{@link #postProcessWebApplicationContext} will be called</li>
     382      * <li>Any {@code ApplicationContextInitializer}s specified through the
     383      * "contextInitializerClasses" init-param or through the {@link
     384      * #setContextInitializers} property will be applied.</li>
     385      * <li>{@link ConfigurableApplicationContext#refresh refresh()} will be called if the
     386      * context implements {@link ConfigurableApplicationContext}</li>
     387      * </ul>
     388      * If the context has already been refreshed, none of the above will occur, under the
     389      * assumption that the user has performed these actions (or not) per their specific
     390      * needs.
     391      * <p>See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
     392      * @param webApplicationContext the context to use
     393      * @see #initWebApplicationContext
     394      * @see #configureAndRefreshWebApplicationContext
     395      * @see org.springframework.web.WebApplicationInitializer
     396      */
     397     public DispatcherServlet(WebApplicationContext webApplicationContext) {
     398         super(webApplicationContext);
     399         setDispatchOptionsRequest(true);
     400     }
     401 
     402 
     403     /**
     404      * Set whether to detect all HandlerMapping beans in this servlet's context. Otherwise,
     405      * just a single bean with name "handlerMapping" will be expected.
     406      * <p>Default is "true". Turn this off if you want this servlet to use a single
     407      * HandlerMapping, despite multiple HandlerMapping beans being defined in the context.
     408      */
     409     public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
     410         this.detectAllHandlerMappings = detectAllHandlerMappings;
     411     }
     412 
     413     /**
     414      * Set whether to detect all HandlerAdapter beans in this servlet's context. Otherwise,
     415      * just a single bean with name "handlerAdapter" will be expected.
     416      * <p>Default is "true". Turn this off if you want this servlet to use a single
     417      * HandlerAdapter, despite multiple HandlerAdapter beans being defined in the context.
     418      */
     419     public void setDetectAllHandlerAdapters(boolean detectAllHandlerAdapters) {
     420         this.detectAllHandlerAdapters = detectAllHandlerAdapters;
     421     }
     422 
     423     /**
     424      * Set whether to detect all HandlerExceptionResolver beans in this servlet's context. Otherwise,
     425      * just a single bean with name "handlerExceptionResolver" will be expected.
     426      * <p>Default is "true". Turn this off if you want this servlet to use a single
     427      * HandlerExceptionResolver, despite multiple HandlerExceptionResolver beans being defined in the context.
     428      */
     429     public void setDetectAllHandlerExceptionResolvers(boolean detectAllHandlerExceptionResolvers) {
     430         this.detectAllHandlerExceptionResolvers = detectAllHandlerExceptionResolvers;
     431     }
     432 
     433     /**
     434      * Set whether to detect all ViewResolver beans in this servlet's context. Otherwise,
     435      * just a single bean with name "viewResolver" will be expected.
     436      * <p>Default is "true". Turn this off if you want this servlet to use a single
     437      * ViewResolver, despite multiple ViewResolver beans being defined in the context.
     438      */
     439     public void setDetectAllViewResolvers(boolean detectAllViewResolvers) {
     440         this.detectAllViewResolvers = detectAllViewResolvers;
     441     }
     442 
     443     /**
     444      * Set whether to throw a NoHandlerFoundException when no Handler was found for this request.
     445      * This exception can then be caught with a HandlerExceptionResolver or an
     446      * {@code @ExceptionHandler} controller method.
     447      * <p>Note that if {@link org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler}
     448      * is used, then requests will always be forwarded to the default servlet and a
     449      * NoHandlerFoundException would never be thrown in that case.
     450      * <p>Default is "false", meaning the DispatcherServlet sends a NOT_FOUND error through the
     451      * Servlet response.
     452      * @since 4.0
     453      */
     454     public void setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound) {
     455         this.throwExceptionIfNoHandlerFound = throwExceptionIfNoHandlerFound;
     456     }
     457 
     458     /**
     459      * Set whether to perform cleanup of request attributes after an include request, that is,
     460      * whether to reset the original state of all request attributes after the DispatcherServlet
     461      * has processed within an include request. Otherwise, just the DispatcherServlet's own
     462      * request attributes will be reset, but not model attributes for JSPs or special attributes
     463      * set by views (for example, JSTL's).
     464      * <p>Default is "true", which is strongly recommended. Views should not rely on request attributes
     465      * having been set by (dynamic) includes. This allows JSP views rendered by an included controller
     466      * to use any model attributes, even with the same names as in the main JSP, without causing side
     467      * effects. Only turn this off for special needs, for example to deliberately allow main JSPs to
     468      * access attributes from JSP views rendered by an included controller.
     469      */
     470     public void setCleanupAfterInclude(boolean cleanupAfterInclude) {
     471         this.cleanupAfterInclude = cleanupAfterInclude;
     472     }
     473 
     474 
     475     /**
     476      * This implementation calls {@link #initStrategies}.
     477      */
     478     @Override
     479     protected void onRefresh(ApplicationContext context) {
     480         initStrategies(context);
     481     }
     482 
     483     /**
     484      * Initialize the strategy objects that this servlet uses.
     485      * <p>May be overridden in subclasses in order to initialize further strategy objects.
     486      */
     487     protected void initStrategies(ApplicationContext context) {
     488         initMultipartResolver(context);
     489         initLocaleResolver(context);
     490         initThemeResolver(context);
     491         initHandlerMappings(context);
     492         initHandlerAdapters(context);
     493         initHandlerExceptionResolvers(context);
     494         initRequestToViewNameTranslator(context);
     495         initViewResolvers(context);
     496         initFlashMapManager(context);
     497     }
     498 
     499     /**
     500      * Initialize the MultipartResolver used by this class.
     501      * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
     502      * no multipart handling is provided.
     503      */
     504     private void initMultipartResolver(ApplicationContext context) {
     505         try {
     506             this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
     507             if (logger.isDebugEnabled()) {
     508                 logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
     509             }
     510         }
     511         catch (NoSuchBeanDefinitionException ex) {
     512             // Default is no multipart resolver.
     513             this.multipartResolver = null;
     514             if (logger.isDebugEnabled()) {
     515                 logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
     516                         "': no multipart request handling provided");
     517             }
     518         }
     519     }
     520 
     521     /**
     522      * Initialize the LocaleResolver used by this class.
     523      * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
     524      * we default to AcceptHeaderLocaleResolver.
     525      */
     526     private void initLocaleResolver(ApplicationContext context) {
     527         try {
     528             this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
     529             if (logger.isDebugEnabled()) {
     530                 logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
     531             }
     532         }
     533         catch (NoSuchBeanDefinitionException ex) {
     534             // We need to use the default.
     535             this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
     536             if (logger.isDebugEnabled()) {
     537                 logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
     538                         "': using default [" + this.localeResolver + "]");
     539             }
     540         }
     541     }
     542 
     543     /**
     544      * Initialize the ThemeResolver used by this class.
     545      * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
     546      * we default to a FixedThemeResolver.
     547      */
     548     private void initThemeResolver(ApplicationContext context) {
     549         try {
     550             this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
     551             if (logger.isDebugEnabled()) {
     552                 logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
     553             }
     554         }
     555         catch (NoSuchBeanDefinitionException ex) {
     556             // We need to use the default.
     557             this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
     558             if (logger.isDebugEnabled()) {
     559                 logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME +
     560                         "': using default [" + this.themeResolver + "]");
     561             }
     562         }
     563     }
     564 
     565     /**
     566      * Initialize the HandlerMappings used by this class.
     567      * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
     568      * we default to BeanNameUrlHandlerMapping.
     569      */
     570     private void initHandlerMappings(ApplicationContext context) {
     571         this.handlerMappings = null;
     572 
     573         if (this.detectAllHandlerMappings) {
     574             // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
     575             Map<String, HandlerMapping> matchingBeans =
     576                     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
     577             if (!matchingBeans.isEmpty()) {
     578                 this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
     579                 // We keep HandlerMappings in sorted order.
     580                 AnnotationAwareOrderComparator.sort(this.handlerMappings);
     581             }
     582         }
     583         else {
     584             try {
     585                 HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
     586                 this.handlerMappings = Collections.singletonList(hm);
     587             }
     588             catch (NoSuchBeanDefinitionException ex) {
     589                 // Ignore, we'll add a default HandlerMapping later.
     590             }
     591         }
     592 
     593         // Ensure we have at least one HandlerMapping, by registering
     594         // a default HandlerMapping if no other mappings are found.
     595         if (this.handlerMappings == null) {
     596             this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
     597             if (logger.isDebugEnabled()) {
     598                 logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
     599             }
     600         }
     601     }
     602 
     603     /**
     604      * Initialize the HandlerAdapters used by this class.
     605      * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
     606      * we default to SimpleControllerHandlerAdapter.
     607      */
     608     private void initHandlerAdapters(ApplicationContext context) {
     609         this.handlerAdapters = null;
     610 
     611         if (this.detectAllHandlerAdapters) {
     612             // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
     613             Map<String, HandlerAdapter> matchingBeans =
     614                     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
     615             if (!matchingBeans.isEmpty()) {
     616                 this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
     617                 // We keep HandlerAdapters in sorted order.
     618                 AnnotationAwareOrderComparator.sort(this.handlerAdapters);
     619             }
     620         }
     621         else {
     622             try {
     623                 HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
     624                 this.handlerAdapters = Collections.singletonList(ha);
     625             }
     626             catch (NoSuchBeanDefinitionException ex) {
     627                 // Ignore, we'll add a default HandlerAdapter later.
     628             }
     629         }
     630 
     631         // Ensure we have at least some HandlerAdapters, by registering
     632         // default HandlerAdapters if no other adapters are found.
     633         if (this.handlerAdapters == null) {
     634             this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
     635             if (logger.isDebugEnabled()) {
     636                 logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
     637             }
     638         }
     639     }
     640 
     641     /**
     642      * Initialize the HandlerExceptionResolver used by this class.
     643      * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
     644      * we default to no exception resolver.
     645      */
     646     private void initHandlerExceptionResolvers(ApplicationContext context) {
     647         this.handlerExceptionResolvers = null;
     648 
     649         if (this.detectAllHandlerExceptionResolvers) {
     650             // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
     651             Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
     652                     .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
     653             if (!matchingBeans.isEmpty()) {
     654                 this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values());
     655                 // We keep HandlerExceptionResolvers in sorted order.
     656                 AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
     657             }
     658         }
     659         else {
     660             try {
     661                 HandlerExceptionResolver her =
     662                         context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
     663                 this.handlerExceptionResolvers = Collections.singletonList(her);
     664             }
     665             catch (NoSuchBeanDefinitionException ex) {
     666                 // Ignore, no HandlerExceptionResolver is fine too.
     667             }
     668         }
     669 
     670         // Ensure we have at least some HandlerExceptionResolvers, by registering
     671         // default HandlerExceptionResolvers if no other resolvers are found.
     672         if (this.handlerExceptionResolvers == null) {
     673             this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
     674             if (logger.isDebugEnabled()) {
     675                 logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");
     676             }
     677         }
     678     }
     679 
     680     /**
     681      * Initialize the RequestToViewNameTranslator used by this servlet instance.
     682      * <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
     683      */
     684     private void initRequestToViewNameTranslator(ApplicationContext context) {
     685         try {
     686             this.viewNameTranslator =
     687                     context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
     688             if (logger.isDebugEnabled()) {
     689                 logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
     690             }
     691         }
     692         catch (NoSuchBeanDefinitionException ex) {
     693             // We need to use the default.
     694             this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
     695             if (logger.isDebugEnabled()) {
     696                 logger.debug("Unable to locate RequestToViewNameTranslator with name '" +
     697                         REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator +
     698                         "]");
     699             }
     700         }
     701     }
     702 
     703     /**
     704      * Initialize the ViewResolvers used by this class.
     705      * <p>If no ViewResolver beans are defined in the BeanFactory for this
     706      * namespace, we default to InternalResourceViewResolver.
     707      * 通过该类初始化ViewResolvers,若BeanFactory里面未定义ViewResolver的beans,
     708      * 则默认使用InternalResourceViewResolver。
     709      */
     710     private void initViewResolvers(ApplicationContext context) {
     711         //初始化viewResolvers
     712         this.viewResolvers = null;
     713         //查找ApplicationContext(包括祖先上下文)中所有的ViewResolvers
     714         if (this.detectAllViewResolvers) {
     715             // Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
     716             Map<String, ViewResolver> matchingBeans =
     717                     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
     718             //若ViewResolvers存在,则将其放入ArrayList中并进行排序操作
     719             if (!matchingBeans.isEmpty()) {
     720                 this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values());
     721                 // We keep ViewResolvers in sorted order.
     722                 AnnotationAwareOrderComparator.sort(this.viewResolvers);
     723             }
     724         }
     725         else {   //若ApplicationContext(包括祖先上下文)中没有ViewResolvers,则使用viewResolver
     726             try {
     727                 ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
     728                 this.viewResolvers = Collections.singletonList(vr);
     729             }
     730             catch (NoSuchBeanDefinitionException ex) {
     731                 // Ignore, we'll add a default ViewResolver later.
     732             }
     733         }
     734         // Ensure we have at least one ViewResolver, by registering
     735         // a default ViewResolver if no other resolvers are found.
     736         //确保至少有一个ViewResolver,若果没有resolvers查到的话就注册一个默认的ViewResolver
     737         if (this.viewResolvers == null) {
     738             this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
     739             if (logger.isDebugEnabled()) {
     740                 logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
     741             }
     742         }
     743     }
     744 
     745     /**
     746      * Initialize the {@link FlashMapManager} used by this servlet instance.
     747      * <p>If no implementation is configured then we default to
     748      * {@code org.springframework.web.servlet.support.DefaultFlashMapManager}.
     749      */
     750     private void initFlashMapManager(ApplicationContext context) {
     751         try {
     752             this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
     753             if (logger.isDebugEnabled()) {
     754                 logger.debug("Using FlashMapManager [" + this.flashMapManager + "]");
     755             }
     756         }
     757         catch (NoSuchBeanDefinitionException ex) {
     758             // We need to use the default.
     759             this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
     760             if (logger.isDebugEnabled()) {
     761                 logger.debug("Unable to locate FlashMapManager with name '" +
     762                         FLASH_MAP_MANAGER_BEAN_NAME + "': using default [" + this.flashMapManager + "]");
     763             }
     764         }
     765     }
     766 
     767     /**
     768      * Return this servlet's ThemeSource, if any; else return {@code null}.
     769      * <p>Default is to return the WebApplicationContext as ThemeSource,
     770      * provided that it implements the ThemeSource interface.
     771      * @return the ThemeSource, if any
     772      * @see #getWebApplicationContext()
     773      */
     774     public final ThemeSource getThemeSource() {
     775         if (getWebApplicationContext() instanceof ThemeSource) {
     776             return (ThemeSource) getWebApplicationContext();
     777         }
     778         else {
     779             return null;
     780         }
     781     }
     782 
     783     /**
     784      * Obtain this servlet's MultipartResolver, if any.
     785      * @return the MultipartResolver used by this servlet, or {@code null} if none
     786      * (indicating that no multipart support is available)
     787      */
     788     public final MultipartResolver getMultipartResolver() {
     789         return this.multipartResolver;
     790     }
     791 
     792     /**
     793      * Return the default strategy object for the given strategy interface.
     794      * <p>The default implementation delegates to {@link #getDefaultStrategies},
     795      * expecting a single object in the list.
     796      * @param context the current WebApplicationContext
     797      * @param strategyInterface the strategy interface
     798      * @return the corresponding strategy object
     799      * @see #getDefaultStrategies
     800      */
     801     protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
     802         List<T> strategies = getDefaultStrategies(context, strategyInterface);
     803         if (strategies.size() != 1) {
     804             throw new BeanInitializationException(
     805                     "DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
     806         }
     807         return strategies.get(0);
     808     }
     809 
     810     /**
     811      * Create a List of default strategy objects for the given strategy interface.
     812      * <p>The default implementation uses the "DispatcherServlet.properties" file (in the same
     813      * package as the DispatcherServlet class) to determine the class names. It instantiates
     814      * the strategy objects through the context's BeanFactory.
     815      * @param context the current WebApplicationContext
     816      * @param strategyInterface the strategy interface
     817      * @return the List of corresponding strategy objects
     818      */
     819     @SuppressWarnings("unchecked")
     820     protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
     821         String key = strategyInterface.getName();
     822         String value = defaultStrategies.getProperty(key);
     823         if (value != null) {
     824             String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
     825             List<T> strategies = new ArrayList<T>(classNames.length);
     826             for (String className : classNames) {
     827                 try {
     828                     Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
     829                     Object strategy = createDefaultStrategy(context, clazz);
     830                     strategies.add((T) strategy);
     831                 }
     832                 catch (ClassNotFoundException ex) {
     833                     throw new BeanInitializationException(
     834                             "Could not find DispatcherServlet's default strategy class [" + className +
     835                                     "] for interface [" + key + "]", ex);
     836                 }
     837                 catch (LinkageError err) {
     838                     throw new BeanInitializationException(
     839                             "Error loading DispatcherServlet's default strategy class [" + className +
     840                                     "] for interface [" + key + "]: problem with class file or dependent class", err);
     841                 }
     842             }
     843             return strategies;
     844         }
     845         else {
     846             return new LinkedList<T>();
     847         }
     848     }
     849 
     850     /**
     851      * Create a default strategy.
     852      * <p>The default implementation uses
     853      * {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean}.
     854      * @param context the current WebApplicationContext
     855      * @param clazz the strategy implementation class to instantiate
     856      * @return the fully configured strategy instance
     857      * @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory()
     858      * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean
     859      */
     860     protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
     861         return context.getAutowireCapableBeanFactory().createBean(clazz);
     862     }
     863 
     864 
     865     /**
     866      * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
     867      * for the actual dispatching.
     868      */
     869     @Override
     870     protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
     871         if (logger.isDebugEnabled()) {
     872             String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
     873             logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
     874                     " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
     875         }
     876 
     877         // Keep a snapshot of the request attributes in case of an include,
     878         // to be able to restore the original attributes after the include.
     879         Map<String, Object> attributesSnapshot = null;
     880         if (WebUtils.isIncludeRequest(request)) {
     881             attributesSnapshot = new HashMap<String, Object>();
     882             Enumeration<?> attrNames = request.getAttributeNames();
     883             while (attrNames.hasMoreElements()) {
     884                 String attrName = (String) attrNames.nextElement();
     885                 if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
     886                     attributesSnapshot.put(attrName, request.getAttribute(attrName));
     887                 }
     888             }
     889         }
     890 
     891         // Make framework objects available to handlers and view objects.
     892         request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
     893         request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
     894         request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
     895         request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
     896 
     897         FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
     898         if (inputFlashMap != null) {
     899             request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
     900         }
     901         request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
     902         request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
     903 
     904         try {
     905             doDispatch(request, response);
     906         }
     907         finally {
     908             if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
     909                 // Restore the original attribute snapshot, in case of an include.
     910                 if (attributesSnapshot != null) {
     911                     restoreAttributesAfterInclude(request, attributesSnapshot);
     912                 }
     913             }
     914         }
     915     }
     916 
     917     /**
     918      * Process the actual dispatching to the handler.
     919      * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
     920      * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
     921      * to find the first that supports the handler class.
     922      * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
     923      * themselves to decide which methods are acceptable.
     924      * 处理分发请求。处理程序将通过应用servlet的HandlerMappings来获得。HandlerAdapter将通过查询servlet
     925      * 安装的HandlerAdapter获得。所有的HTTP方法都被该方法处理。这取决于handleradapter或handler。
     926      * 自己决定哪些方法是可以接受的。
     927      * @param request current HTTP request
     928      * @param response current HTTP response
     929      * @throws Exception in case of any kind of processing failure
     930      */
     931     protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     932         HttpServletRequest processedRequest = request;//获取请求
     933         HandlerExecutionChain mappedHandler = null;//初始化Hadler处理链
     934         boolean multipartRequestParsed = false;
     935         //实例化web异步管理类
     936         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
     937 
     938         try {
     939             ModelAndView mv = null;//初始化ModelAndView
     940             Exception dispatchException = null;//初始化分发异常
     941 
     942             try {
     943                 processedRequest = checkMultipart(request);
     944                 multipartRequestParsed = (processedRequest != request);
     945 
     946                 // Determine handler for the current request.确定当前请求的处理程序
     947                 mappedHandler = getHandler(processedRequest);
     948                 if (mappedHandler == null || mappedHandler.getHandler() == null) {
     949                     noHandlerFound(processedRequest, response);
     950                     return;
     951                 }
     952 
     953                 // Determine handler adapter for the current request.确定当前请求的处理程序适配器
     954                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
     955 
     956                 // Process last-modified header, if supported by the handler.
     957                 String method = request.getMethod();
     958                 boolean isGet = "GET".equals(method);
     959                 if (isGet || "HEAD".equals(method)) {
     960                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
     961                     if (logger.isDebugEnabled()) {
     962                         logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
     963                     }
     964                     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
     965                         return;
     966                     }
     967                 }
     968 
     969                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
     970                     return;
     971                 }
     972 
     973                 // Actually invoke the handler.实际调用处理程序。
     974                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
     975                 //当前请求对应的handler选择使用异步的方式处理当前请求
     976                 if (asyncManager.isConcurrentHandlingStarted()) {
     977                     return;
     978                 }
     979 
     980                 applyDefaultViewName(processedRequest, mv);
     981                 mappedHandler.applyPostHandle(processedRequest, response, mv);
     982             }
     983             catch (Exception ex) {
     984                 dispatchException = ex;
     985             }
     986             catch (Throwable err) {
     987                 // As of 4.3, we're processing Errors thrown from handler methods as well,
     988                 // making them available for @ExceptionHandler methods and other scenarios.
     989                 dispatchException = new NestedServletException("Handler dispatch failed", err);
     990             }
     991             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
     992         }
     993         catch (Exception ex) {
     994             triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
     995         }
     996         catch (Throwable err) {
     997             triggerAfterCompletion(processedRequest, response, mappedHandler,
     998                     new NestedServletException("Handler processing failed", err));
     999         }
    1000         finally {
    1001             if (asyncManager.isConcurrentHandlingStarted()) {
    1002                 // Instead of postHandle and afterCompletion
    1003                 if (mappedHandler != null) {
    1004                     mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    1005                 }
    1006             }
    1007             else {
    1008                 // Clean up any resources used by a multipart request.清理文件上传用到的任何资源
    1009                 if (multipartRequestParsed) {
    1010                     cleanupMultipart(processedRequest);
    1011                 }
    1012             }
    1013         }
    1014     }
    1015 
    1016     /**
    1017      * Do we need view name translation?
    1018      */
    1019     private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
    1020         if (mv != null && !mv.hasView()) {
    1021             mv.setViewName(getDefaultViewName(request));
    1022         }
    1023     }
    1024 
    1025     /**
    1026      * Handle the result of handler selection and handler invocation, which is
    1027      * either a ModelAndView or an Exception to be resolved to a ModelAndView.
    1028      * 处理选择的handler或者回调的handler的结果,要么是一个ModelAndView,要么是一个异常。
    1029      */
    1030     private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
    1031             HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
    1032 
    1033         boolean errorView = false;
    1034         //若发生了异常,根据异常的类型做不同处理
    1035         if (exception != null) {
    1036             if (exception instanceof ModelAndViewDefiningException) {
    1037                 logger.debug("ModelAndViewDefiningException encountered", exception);
    1038                 mv = ((ModelAndViewDefiningException) exception).getModelAndView();
    1039             }
    1040             else {
    1041                 Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
    1042                 mv = processHandlerException(request, response, handler, exception);
    1043                 errorView = (mv != null);
    1044             }
    1045         }
    1046 
    1047         // Did the handler return a view to render?
    1048         //判断handler是否返回了用于渲染的视图
    1049         if (mv != null && !mv.wasCleared()) {
    1050             render(mv, request, response);//渲染给定的ModelAndView
    1051             if (errorView) {
    1052                 WebUtils.clearErrorRequestAttributes(request);
    1053             }
    1054         }
    1055         else {  //无ModelAndView返回
    1056             if (logger.isDebugEnabled()) {
    1057                 logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
    1058                         "': assuming HandlerAdapter completed request handling");
    1059             }
    1060         }
    1061         //若handler以异步方式处理请求,则返回
    1062         if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
    1063             // Concurrent handling started during a forward
    1064             return;
    1065         }
    1066         //handler执行链不为空,则在完成后触发映射的handler拦截器
    1067         if (mappedHandler != null) {
    1068             mappedHandler.triggerAfterCompletion(request, response, null);
    1069         }
    1070     }
    1071 
    1072     /**
    1073      * Build a LocaleContext for the given request, exposing the request's primary locale as current locale.
    1074      * <p>The default implementation uses the dispatcher's LocaleResolver to obtain the current locale,
    1075      * which might change during a request.
    1076      * @param request current HTTP request
    1077      * @return the corresponding LocaleContext
    1078      */
    1079     @Override
    1080     protected LocaleContext buildLocaleContext(final HttpServletRequest request) {
    1081         if (this.localeResolver instanceof LocaleContextResolver) {
    1082             return ((LocaleContextResolver) this.localeResolver).resolveLocaleContext(request);
    1083         }
    1084         else {
    1085             return new LocaleContext() {
    1086                 @Override
    1087                 public Locale getLocale() {
    1088                     return localeResolver.resolveLocale(request);
    1089                 }
    1090             };
    1091         }
    1092     }
    1093 
    1094     /**
    1095      * Convert the request into a multipart request, and make multipart resolver available.
    1096      * <p>If no multipart resolver is set, simply use the existing request.
    1097      * 将请求转成文件上传请求并且可以获取文件上传解析器
    1098      * 如果没有设置文件上传解析器,那就使用已存在的请求。
    1099      * @param request current HTTP request
    1100      * @return the processed request (multipart wrapper if necessary)
    1101      * @see MultipartResolver#resolveMultipart
    1102      */
    1103     protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
    1104         //存在multipartResolver并且是multipart请求
    1105         if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
    1106             if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
    1107                 logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
    1108                         "this typically results from an additional MultipartFilter in web.xml");
    1109             }
    1110             else if (hasMultipartException(request) ) {
    1111                 logger.debug("Multipart resolution failed for current request before - " +
    1112                         "skipping re-resolution for undisturbed error rendering");
    1113             }
    1114             else {
    1115                 try {
    1116                     return this.multipartResolver.resolveMultipart(request);
    1117                 }
    1118                 catch (MultipartException ex) {
    1119                     if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
    1120                         logger.debug("Multipart resolution failed for error dispatch", ex);
    1121                         // Keep processing error dispatch with regular request handle below
    1122                     }
    1123                     else {
    1124                         throw ex;
    1125                     }
    1126                 }
    1127             }
    1128         }
    1129         // If not returned before: return original request.
    1130         return request;
    1131     }
    1132 
    1133     /**
    1134      * Check "javax.servlet.error.exception" attribute for a multipart exception.
    1135      * 检查是否有MultipartException
    1136      */
    1137     private boolean hasMultipartException(HttpServletRequest request) {
    1138         Throwable error = (Throwable) request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE);
    1139         while (error != null) {
    1140             if (error instanceof MultipartException) {
    1141                 return true;
    1142             }
    1143             error = error.getCause();
    1144         }
    1145         return false;
    1146     }
    1147 
    1148     /**
    1149      * Clean up any resources used by the given multipart request (if any).
    1150      * @param request current HTTP request
    1151      * @see MultipartResolver#cleanupMultipart
    1152      */
    1153     protected void cleanupMultipart(HttpServletRequest request) {
    1154         MultipartHttpServletRequest multipartRequest =
    1155                 WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
    1156         if (multipartRequest != null) {
    1157             this.multipartResolver.cleanupMultipart(multipartRequest);
    1158         }
    1159     }
    1160 
    1161     /**
    1162      * Return the HandlerExecutionChain for this request.
    1163      * 返回请求对应的handler执行链
    1164      * <p>Tries all handler mappings in order.
    1165      * @param request current HTTP request
    1166      * @return the HandlerExecutionChain, or {@code null} if no handler could be found
    1167      */
    1168     protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    1169         for (HandlerMapping hm : this.handlerMappings) {
    1170             if (logger.isTraceEnabled()) {
    1171                 logger.trace(
    1172                         "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
    1173             }
    1174             HandlerExecutionChain handler = hm.getHandler(request);
    1175             if (handler != null) {
    1176                 return handler;
    1177             }
    1178         }
    1179         return null;
    1180     }
    1181 
    1182     /**
    1183      * No handler found -> set appropriate HTTP response status.
    1184      * @param request current HTTP request
    1185      * @param response current HTTP response
    1186      * @throws Exception if preparing the response failed
    1187      */
    1188     protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
    1189         if (pageNotFoundLogger.isWarnEnabled()) {
    1190             pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) +
    1191                     "] in DispatcherServlet with name '" + getServletName() + "'");
    1192         }
    1193         if (this.throwExceptionIfNoHandlerFound) {
    1194             throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
    1195                     new ServletServerHttpRequest(request).getHeaders());
    1196         }
    1197         else {
    1198             response.sendError(HttpServletResponse.SC_NOT_FOUND);
    1199         }
    1200     }
    1201 
    1202     /**
    1203      * Return the HandlerAdapter for this handler object.
    1204      * 返回handler对象的handler适配器
    1205      * @param handler the handler object to find an adapter for
    1206      * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
    1207      */
    1208     protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    1209         for (HandlerAdapter ha : this.handlerAdapters) {
    1210             if (logger.isTraceEnabled()) {
    1211                 logger.trace("Testing handler adapter [" + ha + "]");
    1212             }
    1213             if (ha.supports(handler)) {
    1214                 return ha;
    1215             }
    1216         }
    1217         throw new ServletException("No adapter for handler [" + handler +
    1218                 "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    1219     }
    1220 
    1221     /**
    1222      * Determine an error ModelAndView via the registered HandlerExceptionResolvers.
    1223      * @param request current HTTP request
    1224      * @param response current HTTP response
    1225      * @param handler the executed handler, or {@code null} if none chosen at the time of the exception
    1226      * (for example, if multipart resolution failed)
    1227      * @param ex the exception that got thrown during handler execution
    1228      * @return a corresponding ModelAndView to forward to
    1229      * @throws Exception if no error ModelAndView found
    1230      */
    1231     protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
    1232             Object handler, Exception ex) throws Exception {
    1233 
    1234         // Check registered HandlerExceptionResolvers...
    1235         ModelAndView exMv = null;
    1236         for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
    1237             exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
    1238             if (exMv != null) {
    1239                 break;
    1240             }
    1241         }
    1242         if (exMv != null) {
    1243             if (exMv.isEmpty()) {
    1244                 request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
    1245                 return null;
    1246             }
    1247             // We might still need view name translation for a plain error model...
    1248             if (!exMv.hasView()) {
    1249                 exMv.setViewName(getDefaultViewName(request));
    1250             }
    1251             if (logger.isDebugEnabled()) {
    1252                 logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
    1253             }
    1254             WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
    1255             return exMv;
    1256         }
    1257 
    1258         throw ex;
    1259     }
    1260 
    1261     /**
    1262      * Render the given ModelAndView.
    1263      * <p>This is the last stage in handling a request. It may involve resolving the view by name.
    1264      * 根据给定的ModelAndView进行渲染。这是处理请求的最后一步,涉及到通过名称解析视图。
    1265      * @param mv the ModelAndView to render
    1266      * @param request current HTTP servlet request
    1267      * @param response current HTTP servlet response
    1268      * @throws ServletException if view is missing or cannot be resolved
    1269      * @throws Exception if there's a problem rendering the view
    1270      */
    1271     protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    1272         // Determine locale for request and apply it to the response.
    1273         Locale locale = this.localeResolver.resolveLocale(request);
    1274         response.setLocale(locale);
    1275 
    1276         View view;
    1277         //判断是否是视图引用
    1278         if (mv.isReference()) {
    1279             // We need to resolve the view name.
    1280             //将视图名称解析为一个view对象(等待渲染),为null则抛出无法解析异常
    1281             view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
    1282             if (view == null) {
    1283                 throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
    1284                         "' in servlet with name '" + getServletName() + "'");
    1285             }
    1286         }
    1287         else {
    1288             // No need to lookup: the ModelAndView object contains the actual View object.
    1289             //若是非视图引用,则直接可以从ModelAndView对象中获取真实的View对象
    1290             view = mv.getView();
    1291             if (view == null) {
    1292                 throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
    1293                         "View object in servlet with name '" + getServletName() + "'");
    1294             }
    1295         }
    1296 
    1297         // Delegate to the View object for rendering.
    1298         //委托到视图对象进行呈现。
    1299         if (logger.isDebugEnabled()) {
    1300             logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
    1301         }
    1302         try {
    1303             if (mv.getStatus() != null) {
    1304                 response.setStatus(mv.getStatus().value());//设置http响应状态
    1305             }
    1306             /**
    1307              * The first step will be preparing the request: In the JSP case, this would mean
    1308              * setting model objects as request attributes. The second step will be the actual
    1309              * rendering of the view, for example including the JSP via a RequestDispatcher.
    1310              * 第一步是准备request:如果是jsp页面,则意味着将model对象设置为request属性。第二步
    1311              * 将是真正的渲染视图,举例来说,JSP通过一个RequestDispatcher(RequestDispatcher是一个
    1312              * Web资源的包装器,可以用来把当前request传递到该资源,或者把新的资源包括到当前响应中。)。
    1313             */
    1314             view.render(mv.getModelInternal(), request, response);//根据特定的model渲染视图
    1315         }
    1316         catch (Exception ex) {
    1317             if (logger.isDebugEnabled()) {
    1318                 logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
    1319                         getServletName() + "'", ex);
    1320             }
    1321             throw ex;
    1322         }
    1323     }
    1324 
    1325     /**
    1326      * Translate the supplied request into a default view name.
    1327      * 根据提供的请求得到默认的视图名称
    1328      * @param request current HTTP servlet request
    1329      * @return the view name (or {@code null} if no default found)
    1330      * @throws Exception if view name translation failed
    1331      */
    1332     protected String getDefaultViewName(HttpServletRequest request) throws Exception {
    1333         return this.viewNameTranslator.getViewName(request);
    1334     }
    1335 
    1336     /**
    1337      * Resolve the given view name into a View object (to be rendered).
    1338      * 根据给定的视图名称将其变成一个view对象(等待渲染)
    1339      * <p>The default implementations asks all ViewResolvers of this dispatcher.
    1340      * Can be overridden for custom resolution strategies, potentially based on
    1341      * specific model attributes or request parameters.
    1342      * @param viewName the name of the view to resolve
    1343      * @param model the model to be passed to the view
    1344      * @param locale the current locale
    1345      * @param request current HTTP servlet request
    1346      * @return the View object, or {@code null} if none found
    1347      * @throws Exception if the view cannot be resolved
    1348      * (typically in case of problems creating an actual View object)
    1349      * @see ViewResolver#resolveViewName
    1350      */
    1351     protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
    1352             HttpServletRequest request) throws Exception {
    1353         //遍历所有的视图解析器,解析出视图名称
    1354         for (ViewResolver viewResolver : this.viewResolvers) {
    1355             View view = viewResolver.resolveViewName(viewName, locale);
    1356             if (view != null) {
    1357                 return view;
    1358             }
    1359         }
    1360         return null;
    1361     }
    1362 
    1363     private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
    1364             HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
    1365 
    1366         if (mappedHandler != null) {
    1367             mappedHandler.triggerAfterCompletion(request, response, ex);
    1368         }
    1369         throw ex;
    1370     }
    1371 
    1372     /**
    1373      * Restore the request attributes after an include.
    1374      * 重新存储请求中的属性
    1375      * @param request current HTTP request
    1376      * @param attributesSnapshot the snapshot of the request attributes before the include
    1377      */
    1378     @SuppressWarnings("unchecked")
    1379     private void restoreAttributesAfterInclude(HttpServletRequest request, Map<?,?> attributesSnapshot) {
    1380         // Need to copy into separate Collection here, to avoid side effects
    1381         // on the Enumeration when removing attributes.
    1382         Set<String> attrsToCheck = new HashSet<String>();
    1383         Enumeration<?> attrNames = request.getAttributeNames();
    1384         while (attrNames.hasMoreElements()) {
    1385             String attrName = (String) attrNames.nextElement();
    1386             if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
    1387                 attrsToCheck.add(attrName);
    1388             }
    1389         }
    1390 
    1391         // Add attributes that may have been removed
    1392         attrsToCheck.addAll((Set<String>) attributesSnapshot.keySet());
    1393 
    1394         // Iterate over the attributes to check, restoring the original value
    1395         // or removing the attribute, respectively, if appropriate.
    1396         for (String attrName : attrsToCheck) {
    1397             Object attrValue = attributesSnapshot.get(attrName);
    1398             if (attrValue == null){
    1399                 request.removeAttribute(attrName);
    1400             }
    1401             else if (attrValue != request.getAttribute(attrName)) {
    1402                 request.setAttribute(attrName, attrValue);
    1403             }
    1404         }
    1405     }
    1406 
    1407     private static String getRequestUri(HttpServletRequest request) {
    1408         String uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
    1409         if (uri == null) {
    1410             uri = request.getRequestURI();
    1411         }
    1412         return uri;
    1413     }
    1414 
    1415 }
  • 相关阅读:
    NOIP2016 天天爱跑步 正解
    NOIP2016 换教室
    iOS开发-14款状态栏(StatusBar)开源软件
    iOS 优化方案浅析
    iOS应用程序多语言本地化解决方案
    iOS开发流程总结
    iOS开发者必备:四款后端服务工具
    iOS开发之加载、滑动翻阅大量图片优化解决方案
    iOS开发之──传感器使用
    iOS开发中的Html解析方法
  • 原文地址:https://www.cnblogs.com/stm32stm32/p/9090827.html
Copyright © 2011-2022 走看看