我们先来了解一个请求是如何被 Spring MVC 处理的,由于整个流程涉及到的代码非常多,所以本文的重点在于解析整体的流程,主要讲解 DispatcherServlet 这个核心类,弄懂了这个流程后,才能更好的理解具体的源码,回过头再来看则会更加的豁然开朗

Spring MVC 处理请求的流程大致如上图所示
以上就是 Spring MVC 处理请求的全过程,上面的流程进行了一定的简化,主要涉及到最核心的组件,还有许多其他组件没有表现出来,不过这并不影响大家对主过程的理解。
在上一篇《WebApplicationContext 容器的初始化》文档讲述 FramworkServlet 的 onRefresh 方法时,该方法由 DispatcherServlet 去实现,会初始化九大组件,如何初始化的这里暂时不展开讨论,默认会从 spring-webmvc 下面的 DispatcherServlet.properties 文件中读取组件的实现类,感兴趣可以先阅读一下源码,后续会依次描述
那么接下来就简单介绍一下 DispatcherServlet 和九大组件:

Spring MVC 对各个组件的职责划分得比较清晰。DispatcherServlet 负责协调,其他组件则各自做分内之事,互不干扰。经过这样的职责划分,代码会便于维护。同时对于源码阅读者来说,也会很友好。可以降低理解源码的难度,使大家能够快速理清主逻辑。这一点值得我们学习。
ThemeResolver 和 FlashMapManager 组件在该系列文档中不会进行讲解,因为几乎接触不到,感兴趣的可以去 Google 一下,嘻嘻~ 笔者没接触过
虽然在上面的整体流程图中,我们看到请求是直接被 DispatcherServlet 所处理,但是实际上,FrameworkServlet 才是真正的入口,再来回顾一个 DispatcherServlet 的类图,如下:

FrameworkServlet 覆盖了 HttpServlet 的以下方法:
这些方法分别处理不同 HTTP 请求类型的请求,最终都会调用另一个 processRequest(HttpServletRequest request, HttpServletResponse response) 方法
其中 doGet、doPost、doPut和doDelete 四个方法是直接调用 processRequest 方法的
service(HttpServletRequest request, HttpServletResponse response) 方法,用于处理请求,方法如下:
- @Override
- protected void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- // <1> 获得请求方法
- HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
- // <2> 处理 PATCH 请求
- if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
- processRequest(request, response);
- }
- // <3> 处理其他类型的请求
- else {
- super.service(request, response);
- }
- }
doOptions(HttpServletRequest request, HttpServletResponse response)方法,用于处理 OPTIONS 类型的请求,方法如下:
- @Override
- protected void doOptions(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- // 如果 dispatchOptionsRequest 为 true ,则处理该请求,默认为 true
- if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {
- // 处理请求
- processRequest(request, response);
- // 如果响应 Header 包含 "Allow" ,则不需要交给父方法处理
- if (response.containsHeader("Allow")) {
- // Proper OPTIONS response coming from a handler - we're done.
- return;
- }
- }
-
- // Use response wrapper in order to always add PATCH to the allowed methods
- // 调用父方法,并在响应 Header 的 "Allow" 增加 PATCH 的值
- super.doOptions(request, new HttpServletResponseWrapper(response) {
- @Override
- public void setHeader(String name, String value) {
- if ("Allow".equals(name)) {
- value = (StringUtils.hasLength(value) ? value + ", " : "") + HttpMethod.PATCH.name();
- }
- super.setHeader(name, value);
- }
- });
- }
使用场景:AJAX 进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全
doTrace(HttpServletRequest request, HttpServletResponse response)方法,用于处理 TRACE 类型的请求,方法如下:
- protected void doTrace(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- // 如果 dispatchTraceRequest 为 true ,则处理该请求,默认为 false
- if (this.dispatchTraceRequest) {
- // 处理请求
- processRequest(request, response);
- // 如果响应的内容类型为 "message/http" ,则不需要交给父方法处理
- if ("message/http".equals(response.getContentType())) {
- // Proper TRACE response coming from a handler - we're done.
- return;
- }
- }
- // 调用父方法
- super.doTrace(request, response);
- }
回显服务器收到的请求,主要用于测试或诊断,笔者目前还没接触过
processRequest(HttpServletRequest request, HttpServletResponse response) 方法,用于处理请求,方法如下:
- protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- // <1> 记录当前时间,用于计算处理请求花费的时间
- long startTime = System.currentTimeMillis();
- // <2> 记录异常,用于保存处理请求过程中发送的异常
- Throwable failureCause = null;
-
- // <3> TODO
- LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
- LocaleContext localeContext = buildLocaleContext(request);
-
- // <4> TODO
- RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
- ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
-
- // <5> TODO
- WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
- asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
-
- // <6> TODO
- initContextHolders(request, localeContext, requestAttributes);
-
- try {
- // <7> 执行真正的逻辑
- doService(request, response);
- }
- catch (ServletException | IOException ex) {
- failureCause = ex; // <8> 记录抛出的异常
- throw ex;
- }
- catch (Throwable ex) {
- failureCause = ex; // <8> 记录抛出的异常
- throw new NestedServletException("Request processing failed", ex);
- }
-
- finally {
- // <9> TODO
- resetContextHolders(request, previousLocaleContext, previousAttributes);
- // <10> TODO
- if (requestAttributes != null) {
- requestAttributes.requestCompleted();
- }
- // <11> 如果日志级别为 DEBUG,则打印请求日志
- logResult(request, response, failureCause, asyncManager);
- // <12> 发布 ServletRequestHandledEvent 请求处理完成事件
- publishRequestHandledEvent(request, response, startTime, failureCause);
- }
- }
<1> 记录当前时间,用于计算处理请求花费的时间
<2> 记录异常,用于保存处理请求过程中发送的异常
<7> 【核心】调用 doService(HttpServletRequest request, HttpServletResponse response) 抽象方法,执行真正的逻辑,由 DispatcherServlet 实现,所以这就是 DispatcherServlet 处理请求的真正入口
<8> 记录执行过程抛出的异常,最终在 finally 的代码段中使用。
<11> 如果日志级别为 DEBUG,则打印请求日志
<12> 调用 publishRequestHandledEvent 方法,通过 WebApplicationContext 发布 ServletRequestHandledEvent 请求处理完成事件,目前好像 Spring MVC 没有监听这个事件,可以自己写一个监听器用于获取请求信息,示例如下:
- @Component
- @Log4j2
- public class ServletRequestHandledEventListener implements ApplicationListener<ServletRequestHandledEvent>{
- @Override
- public void onApplicationEvent(ServletRequestHandledEvent event) {
- log.info("请求描述:{}", event.getDescription());
- log.info("请求路径:{}", event.getRequestUrl());
- log.info("开始时间:{}", event.getTimestamp());
- log.info("请求耗时:{}", event.getProcessingTimeMillis());
- log.info("状 态 码:{}", event.getStatusCode());
- log.info("失败原因:{}", event.getFailureCause());
- }
- }
到这里,FrameworkServlet 算是讲完了,接下来就要开始讲 DispatcherServlet 这个核心类了
org.springframework.web.servlet.DispatcherServlet核心类,作为 Spring MVC 的核心类,承担调度器的角色,协调各个组件进行工作,处理请求,一起来揭开这神秘的面纱吧
- private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
-
- private static final Properties defaultStrategies;
-
- static {
- // Load default strategy implementations from properties file.
- // This is currently strictly internal and not meant to be customized by application developers.
- try {
- ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
- defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
- }
- catch (IOException ex) {
- throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
- }
- }
会从 DispatcherServlet.properties 文件中加载默认的组件实现类,将相关配置加载到 defaultStrategies 中,文件如下:
- ### org.springframework.web.servlet.DispatcherServlet.properties
-
- # Default implementation classes for DispatcherServlet's strategy interfaces.
- # Used as fallback when no matching beans are found in the DispatcherServlet context.
- # Not meant to be customized by application developers.
-
- org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
-
- org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
-
- org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
-
- org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
- org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
-
- org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
- org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
- org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
-
- org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
-
- org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
-
- org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
-
- # Default implementation classes for DispatcherServlet's strategy interfaces.
- # Used as fallback when no matching beans are found in the DispatcherServlet context.
- # Not meant to be customized by application developers.
-
- org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
-
- org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
-
- org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
-
- org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
- org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
-
- org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
- org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
- org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
-
- org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
-
- org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
-
- org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
可以看到各个组件的默认实现类
- /** MultipartResolver used by this servlet. multipart 数据(文件)处理器 */
- @Nullable
- private MultipartResolver multipartResolver;
-
- /** LocaleResolver used by this servlet. 语言处理器,提供国际化的支持 */
- @Nullable
- private LocaleResolver localeResolver;
-
- /** ThemeResolver used by this servlet. 主题处理器,设置需要应用的整体样式 */
- @Nullable
- private ThemeResolver themeResolver;
-
- /** List of HandlerMappings used by this servlet. 处理器匹配器,返回请求对应的处理器和拦截器们 */
- @Nullable
- private List<HandlerMapping> handlerMappings;
-
- /** List of HandlerAdapters used by this servlet. 处理器适配器,用于执行处理器 */
- @Nullable
- private List<HandlerAdapter> handlerAdapters;
-
- /** List of HandlerExceptionResolvers used by this servlet. 异常处理器,用于解析处理器发生的异常 */
- @Nullable
- private List<HandlerExceptionResolver> handlerExceptionResolvers;
-
- /** RequestToViewNameTranslator used by this servlet. 视图名称转换器 */
- @Nullable
- private RequestToViewNameTranslator viewNameTranslator;
-
- /** FlashMapManager used by this servlet. FlashMap 管理器,负责重定向时保存参数到临时存储(默认 Session)中 */
- @Nullable
- private FlashMapManager flashMapManager;
-
- /** List of ViewResolvers used by this servlet. 视图解析器,根据视图名称和语言,获取 View 视图 */
- @Nullable
- private List<ViewResolver> viewResolvers;
-
- public DispatcherServlet() {
- super();
- setDispatchOptionsRequest(true);
- }
-
- public DispatcherServlet(WebApplicationContext webApplicationContext) {
- super(webApplicationContext);
- setDispatchOptionsRequest(true);
- }
定义了九个组件,在组件预览中已经做过简单介绍了
构造方法中都会设置 dispatchOptionsRequest 为 true,在父类 FrameworkServlet 中可以看到,如果请求是 OPTIONS 则会处理请求
onRefresh(ApplicationContext context) 方法,初始化 Spring MVC 的各个组件,方法如下:
- @Override
- protected void onRefresh(ApplicationContext context) {
- initStrategies(context);
- }
-
- /**
- * Initialize the strategy objects that this servlet uses.
- * <p>May be overridden in subclasses in order to initialize further strategy objects.
- */
- protected void initStrategies(ApplicationContext context) {
- // 初始化 MultipartResolver
- initMultipartResolver(context);
- // 初始化 LocaleResolver
- initLocaleResolver(context);
- // 初始化 ThemeResolver
- initThemeResolver(context);
- // 初始化 HandlerMapping
- initHandlerMappings(context);
- // 初始化 HandlerAdapter
- initHandlerAdapters(context);
- // 初始化 HandlerExceptionResolver
- initHandlerExceptionResolvers(context);
- // 初始化 RequestToViewNameTranslator
- initRequestToViewNameTranslator(context);
- // 初始化 ViewResolver
- initViewResolvers(context);
- // 初始化 FlashMapManager
- initFlashMapManager(context);
- }
创建 Servlet WebApplicationContext 容器后会触发该方法,在《WebApplicationContext 容器的初始化》的 FrameworkServlet小节的 onRefresh 方法中提到过
可以看到每个方法会初始化构造方法中的每个组件
doService(HttpServletRequest request, HttpServletResponse response)方法,DispatcherServlet 的处理请求的入口方法,代码如下:
- @Override
- protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
- // <1> 如果日志级别为 DEBUG,则打印请求日志
- logRequest(request);
-
- // Keep a snapshot of the request attributes in case of an include,
- // to be able to restore the original attributes after the include.
- // <2> 保存当前请求中相关属性的一个快照
- Map<String, Object> attributesSnapshot = null;
- if (WebUtils.isIncludeRequest(request)) {
- attributesSnapshot = new HashMap<>();
- Enumeration<?> attrNames = request.getAttributeNames();
- while (attrNames.hasMoreElements()) {
- String attrName = (String) attrNames.nextElement();
- if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
- attributesSnapshot.put(attrName, request.getAttribute(attrName));
- }
- }
- }
-
- // Make framework objects available to handlers and view objects.
- // <3> 设置 Spring 框架中的常用对象到 request 属性中
- request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
- request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
- request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
- request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
-
- // <4> FlashMap 的相关配置
- if (this.flashMapManager != null) {
- FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
- if (inputFlashMap != null) {
- request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
- }
- request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
- request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
- }
-
- try {
- // <5> 执行请求的分发
- doDispatch(request, response);
- }
- finally {
- // <6> 异步处理相关
- if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
- // Restore the original attribute snapshot, in case of an include.
- if (attributesSnapshot != null) {
- restoreAttributesAfterInclude(request, attributesSnapshot);
- }
- }
- }
- }
doDispatch(HttpServletRequest request, HttpServletResponse response) 方法,行请求的分发,在开始看具体的代码实现之前,我们再来回味下这张图片:

这张图,更多的反应的是 DispatcherServlet 的 doDispatch(...) 方法的核心流程,方法如下:
- protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
- HttpServletRequest processedRequest = request;
- HandlerExecutionChain mappedHandler = null;
- boolean multipartRequestParsed = false;
-
- // <1> 获取异步管理器
- WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
-
- try {
- ModelAndView mv = null;
- Exception dispatchException = null;
-
- try {
- // <2> 检测请求是否为上传请求,如果是则通过 multipartResolver 将其封装成 MultipartHttpServletRequest 对象
- processedRequest = checkMultipart(request);
- multipartRequestParsed = (processedRequest != request);
-
- // Determine handler for the current request.
- // <3> 获得请求对应的 HandlerExecutionChain 对象(HandlerMethod 和 HandlerInterceptor 拦截器们)
- mappedHandler = getHandler(processedRequest);
- if (mappedHandler == null) { // <3.1> 如果获取不到,则根据配置抛出异常或返回 404 错误
- noHandlerFound(processedRequest, response);
- return;
- }
-
- // Determine handler adapter for the current request.
- // <4> 获得当前 handler 对应的 HandlerAdapter 对象
- HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
-
- // Process last-modified header, if supported by the handler.
- // <4.1> 处理有Last-Modified请求头的场景
- String method = request.getMethod();
- boolean isGet = "GET".equals(method);
- if (isGet || "HEAD".equals(method)) { // 不清楚为什么要判断方法类型为'HEAD'
- // 获取请求中服务器端最后被修改时间
- long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
- if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
- return;
- }
- }
-
- // <5> 前置处理 拦截器
- // 注意:该方法如果有一个拦截器的前置处理返回false,则开始倒序触发所有的拦截器的 已完成处理
- if (!mappedHandler.applyPreHandle(processedRequest, response)) {
- return;
- }
-
- // Actually invoke the handler.
- // <6> 真正的调用 handler 方法,也就是执行对应的方法,并返回视图
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
-
- // <7> 如果是异步
- if (asyncManager.isConcurrentHandlingStarted()) {
- return;
- }
-
- // <8> 无视图的情况下设置默认视图名称
- applyDefaultViewName(processedRequest, mv);
- // <9> 后置处理 拦截器
- mappedHandler.applyPostHandle(processedRequest, response, mv);
- }
- catch (Exception ex) {
- dispatchException = ex; // <10> 记录异常
- }
- catch (Throwable err) {
- // As of 4.3, we're processing Errors thrown from handler methods as well,
- // making them available for @ExceptionHandler methods and other scenarios.
- dispatchException = new NestedServletException("Handler dispatch failed", err);
- }
- // <11> 处理正常和异常的请求调用结果
- processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
- }
- catch (Exception ex) {
- // <12> 已完成处理 拦截器
- triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
- }
- catch (Throwable err) {
- // <12> 已完成处理 拦截器
- triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err));
- }
- finally {
- // <13.1> Asyn
- if (asyncManager.isConcurrentHandlingStarted()) {
- // Instead of postHandle and afterCompletion
- if (mappedHandler != null) {
- mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
- }
- }
- // <13.1> 如果是上传请求则清理资源
- else {
- // Clean up any resources used by a multipart request.
- if (multipartRequestParsed) {
- cleanupMultipart(processedRequest);
- }
- }
- }
- }
上面将 DispatcherServlet 处理请求的整个流程步骤都列出来了,涉及到的组件分别在后续的文档中将分开进行分析
checkMultipart(HttpServletRequest request) 方法,检测请求是否为上传请求,如果是则通过 multipartResolver 组件将其封装成 MultipartHttpServletRequest 对象
- protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
- // 如果该请求是一个涉及到 multipart (文件)的请求
- if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
- if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
- if (request.getDispatcherType().equals(DispatcherType.REQUEST)) {
- logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
- }
- }
- else if (hasMultipartException(request)) {
- logger.debug("Multipart resolution previously failed for current request - " +
- "skipping re-resolution for undisturbed error rendering");
- }
- else {
- try {
- // 将 HttpServletRequest 请求封装成 MultipartHttpServletRequest 对象,解析请求里面的参数以及文件
- return this.multipartResolver.resolveMultipart(request);
- }
- catch (MultipartException ex) {
- if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
- logger.debug("Multipart resolution failed for error dispatch", ex);
- // Keep processing error dispatch with regular request handle below
- }
- else {
- throw ex;
- }
- }
- }
- }
- // If not returned before: return original request.
- return request;
- }
getHandler(HttpServletRequest request) 方法,通过 HandlerMapping 组件获得请求对应的 HandlerExecutionChain 处理器执行链,包含 HandlerMethod 处理器和 HandlerInterceptor 拦截器们
- @Nullable
- protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- if (this.handlerMappings != null) {
- for (HandlerMapping mapping : this.handlerMappings) {
- HandlerExecutionChain handler = mapping.getHandler(request);
- if (handler != null) {
- return handler;
- }
- }
- }
- return null;
- }
getHandlerAdapter(Object handler) 方法,获得当前处理器对应的 HandlerAdapter 适配器对象
- protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
- if (this.handlerAdapters != null) {
- for (HandlerAdapter adapter : this.handlerAdapters) {
- if (adapter.supports(handler)) {
- return adapter;
- }
- }
- }
- throw new ServletException("No adapter for handler [" + handler +
- "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
- }
applyDefaultViewName(HttpServletRequest request, ModelAndView mv) 方法,ModelAndView 不为空,但是没有视图,则设置默认视图名称
- private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
- if (mv != null && !mv.hasView()) {
- String defaultViewName = getDefaultViewName(request);
- if (defaultViewName != null) {
- mv.setViewName(defaultViewName);
- }
- }
- }
- @Nullable
- protected String getDefaultViewName(HttpServletRequest request) throws Exception {
- // 使用到了 `viewNameTranslator` 视图名称转换器组件
- return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null);
- }
processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) 方法,处理正常和异常的请求调用结果,方法如下:
- private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
- @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
- @Nullable Exception exception) throws Exception {
-
- // <1> 标记是否为处理生成异常的 ModelAndView 对象
- boolean errorView = false;
-
- // <2> 如果该请求出现异常
- if (exception != null) {
- // 情况一,从 ModelAndViewDefiningException 中获得 ModelAndView 对象
- if (exception instanceof ModelAndViewDefiningException) {
- logger.debug("ModelAndViewDefiningException encountered", exception);
- mv = ((ModelAndViewDefiningException) exception).getModelAndView();
- }
- // 情况二,处理异常,生成 ModelAndView 对象
- else {
- Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
- mv = processHandlerException(request, response, handler, exception);
- // 标记 errorView
- errorView = (mv != null);
- }
- }
-
- // Did the handler return a view to render?
- // <3> 是否进行页面渲染
- if (mv != null && !mv.wasCleared()) {
- // <3.1> 渲染页面
- render(mv, request, response);
- // <3.2> 清理请求中的错误消息属性
- // 因为上述的情况二中 processHandlerException 会通过 WebUtils 设置错误消息属性,所以这里得清理一下
- if (errorView) {
- WebUtils.clearErrorRequestAttributes(request);
- }
- }
- else {
- if (logger.isTraceEnabled()) {
- logger.trace("No view rendering, null ModelAndView returned.");
- }
- }
-
- // <4> 如果是异步
- if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
- // Concurrent handling started during a forward
- return;
- }
-
- // <5> 已完成处理 拦截器
- if (mappedHandler != null) {
- mappedHandler.triggerAfterCompletion(request, response, null);
- }
- }
processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 方法,处理异常,生成 ModelAndView 对象
- @Nullable
- protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
- @Nullable Object handler, Exception ex) throws Exception {
-
- // Success and error responses may use different content types
- // 移除 PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE 属性
- request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
-
- // Check registered HandlerExceptionResolvers...
- // <a> 遍历 HandlerExceptionResolver 数组,解析异常,生成 ModelAndView 对象
- ModelAndView exMv = null;
- if (this.handlerExceptionResolvers != null) {
- // 遍历 HandlerExceptionResolver 数组
- for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
- // 解析异常,生成 ModelAndView 对象
- exMv = resolver.resolveException(request, response, handler, ex);
- // 生成成功,结束循环
- if (exMv != null) {
- break;
- }
- }
- }
- // <b> 情况一,生成了 ModelAndView 对象,进行返回
- if (exMv != null) {
- // ModelAndView 对象为空,则返回 null
- if (exMv.isEmpty()) {
- request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
- return null;
- }
- // We might still need view name translation for a plain error model...
- // 没有视图则设置默认视图
- if (!exMv.hasView()) {
- String defaultViewName = getDefaultViewName(request);
- if (defaultViewName != null) {
- exMv.setViewName(defaultViewName);
- }
- }
- // 打印日志
- if (logger.isTraceEnabled()) {
- logger.trace("Using resolved error view: " + exMv, ex);
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Using resolved error view: " + exMv);
- }
- // 设置请求中的错误消息属性
- WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
- return exMv;
- }
-
- // <c> 情况二,未生成 ModelAndView 对象,则抛出异常
- throw ex;
- }
<a> 处,遍历 HandlerExceptionResolver 数组,调用 HandlerExceptionResolver#resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 方法,解析异常,生成 ModelAndView 对象
<b> 处,情况一,生成了 ModelAndView 对象,逻辑比较简单
<c> 处,情况二,未生成 ModelAndView 对象,则抛出异常
render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) 方法,渲染 ModelAndView,方法如下:
- protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
- // Determine locale for request and apply it to the response.
- // <1> 解析 request 中获得 Locale 对象,并设置到 response 中
- Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
- response.setLocale(locale);
-
- // 获得 View 对象
- View view;
- String viewName = mv.getViewName();
- // 情况一,使用 viewName 获得 View 对象
- if (viewName != null) {
- // We need to resolve the view name.
- // <2.1> 使用 viewName 获得 View 对象
- view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
- if (view == null) { // 获取不到,抛出 ServletException 异常
- throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
- "' in servlet with name '" + getServletName() + "'");
- }
- }
- // 情况二,直接使用 ModelAndView 对象的 View 对象
- else {
- // No need to lookup: the ModelAndView object contains the actual View object.
- // <2.2> 直接使用 ModelAndView 对象的 View 对象
- view = mv.getView();
- if (view == null) { // 获取不到,抛出 ServletException 异常
- throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
- "View object in servlet with name '" + getServletName() + "'");
- }
- }
-
- // Delegate to the View object for rendering.
- // 打印日志
- if (logger.isTraceEnabled()) {
- logger.trace("Rendering view [" + view + "] ");
- }
- try {
- // <3> 设置响应的状态码
- if (mv.getStatus() != null) {
- response.setStatus(mv.getStatus().value());
- }
- // <4> 渲染页面
- view.render(mv.getModelInternal(), request, response);
- }
- catch (Exception ex) {
- if (logger.isDebugEnabled()) {
- logger.debug("Error rendering view [" + view + "]", ex);
- }
- throw ex;
- }
- }
本文对 Spring MVC 处理请求的整个过程进行了分析,核心就是通过 DispatcherServlet 协调各个组件工作,处理请求,因为 DispatcherServlet 是一个 Servlet,在 Servlet 容器中,会将请求交由它来处理。
通过本文对 DispatcherServlet 是如何处理请求已经有了一个整体的认识,不过在整个处理过程中涉及到的各个 Spring MVC 组件还没有进行分析,对于许多细节存在疑惑,不要慌,那么接下来会对每一个 Spring MVC 组件进行分析。这样,便于我们对 Spring MVC 的理解,然后再回过头来思考 DispatcherServlet 这个类,能够更好的将这些组件串联在一起。先整体,后局部,逐步逐步抽丝剥茧,看清理透。