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 }