14. SpringMVC执行流程
阅读原文时间:2023年08月21日阅读:1
  • DispatcherServlet:前端控制器,不需要工程师开发,由框架提供

作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求

  • HandlerMapping:处理器映射器,不需要工程师开发,由框架提供

作用:根据请求的 url、method 等信息查找 Handler,即控制器方法

  • Handler:处理器,需要工程师开发

作用:在 DispatcherServlet 的控制下 Handler 对具体的用户请求进行处理

  • HandlerAdapter:**处理器适配器**,不需要工程师开发,由框架提供

作用:通过 HandlerAdapter 对处理器(控制器方法)进行执行

  • ViewResolver:视图解析器,不需要工程师开发,由框架提供

作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、

RedirectView

  • View:视图

作用:将模型数据通过页面展示给用户

DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。

① 初始化 WebApplicationContext

所在类:org.springframework.web.servlet.FrameworkServlet

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
    if (this.webApplicationContext != null) {
        // A context instance was injected at construction time -> use it
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac =(ConfigurableWebApplicationContext) wac;
            if (!cwac.isActive()) {
                // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent -> set
                            // the root application context (if any; may be null) as the parent
                            cwac.setParent(rootContext);
                    }
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    if (wac == null) {
        // No context instance was injected at construction time -> see if one
        // has been registered in the servlet context. If one exists, it is assumed
            // that the parent context (if any) has already been set and that the
            // user has performed any initialization such as setting the context id
            wac = findWebApplicationContext();
    }
    if (wac == null) {
        // No context instance is defined for this servlet -> create a local one
        // 创建WebApplicationContext
        wac = createWebApplicationContext(rootContext);
    }
    if (!this.refreshEventReceived) {
        // Either the context is not a ConfigurableApplicationContext with refresh
            // support or the context injected at construction time had already been
            // refreshed -> trigger initial onRefresh manually here.
            synchronized (this.onRefreshMonitor) {
            // 刷新WebApplicationContext
            onRefresh(wac);
        }
    }
    if (this.publishContext) {
        // Publish the context as a servlet context attribute.
        // 将IOC容器在应用域共享
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }
    return wac;
}

② 创建 WebApplicationContext

所在类:org.springframework.web.servlet.FrameworkServlet

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
 &nbsp; &nbsp;Class<?> contextClass = getContextClass();
 &nbsp; &nbsp;if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass))
 &nbsp;  {
 &nbsp; &nbsp; &nbsp; &nbsp;throw new ApplicationContextException("Fatal initialization error in servlet with name '" +getServletName() +
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"': custom WebApplicationContext class [" + contextClass.getName() +
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"] is not of type ConfigurableWebApplicationContext");
 &nbsp;  }
 &nbsp; &nbsp;// 通过反射创建 IOC 容器对象
 &nbsp; &nbsp;ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
 &nbsp; &nbsp;wac.setEnvironment(getEnvironment());
 &nbsp; &nbsp;// 设置父容器
 &nbsp; &nbsp;wac.setParent(parent);
 &nbsp; &nbsp;String configLocation = getContextConfigLocation();
 &nbsp; &nbsp;if (configLocation != null) {
 &nbsp; &nbsp; &nbsp; &nbsp;wac.setConfigLocation(configLocation);
 &nbsp;  }
 &nbsp; &nbsp;configureAndRefreshWebApplicationContext(wac);
 &nbsp; &nbsp;return wac;
}

③DispatcherServlet 初始化策略

FrameworkServlet 创建 WebApplicationContext 后,刷新容器,调用 onRefresh(wac),此方法在

DispatcherServlet 中进行了重写,调用了 initStrategies(context)方法,初始化策略,即初始化

DispatcherServlet 的各个组件

所在类:org.springframework.web.servlet.DispatcherServlet

protected void initStrategies(ApplicationContext context) {
 &nbsp; &nbsp;initMultipartResolver(context);
 &nbsp; &nbsp;initLocaleResolver(context);
 &nbsp; &nbsp;initThemeResolver(context);
 &nbsp; &nbsp;initHandlerMappings(context);
 &nbsp; &nbsp;initHandlerAdapters(context);
 &nbsp; &nbsp;initHandlerExceptionResolvers(context);
 &nbsp; &nbsp;initRequestToViewNameTranslator(context);
 &nbsp; &nbsp;initViewResolvers(context);
 &nbsp; &nbsp;initFlashMapManager(context);
}

①processRequest()

FrameworkServlet 重写 HttpServlet 中的 service()和 doXxx(),这些方法中调用了

processRequest(request, response)

所在类:org.springframework.web.servlet.FrameworkServlet

protected final void processRequest(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException
{
 &nbsp; &nbsp;long startTime = System.currentTimeMillis();
 &nbsp; &nbsp;Throwable failureCause = null;
 &nbsp; &nbsp;LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
 &nbsp; &nbsp;LocaleContext localeContext = buildLocaleContext(request);
 &nbsp; &nbsp;RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
 &nbsp; &nbsp;ServletRequestAttributes requestAttributes = buildRequestAttributes(request,response, previousAttributes);
 &nbsp; &nbsp;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 &nbsp; &nbsp;asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(),new RequestBindingInterceptor());
 &nbsp; &nbsp;initContextHolders(request, localeContext, requestAttributes);
 &nbsp; &nbsp;try {
 &nbsp; &nbsp; &nbsp; &nbsp;// 执行服务,doService()是一个抽象方法,在DispatcherServlet中进行了重写
 &nbsp; &nbsp; &nbsp; &nbsp;doService(request, response);
 &nbsp;  }
 &nbsp; &nbsp;catch (ServletException | IOException ex) {
 &nbsp; &nbsp; &nbsp; &nbsp;failureCause = ex;
 &nbsp; &nbsp; &nbsp; &nbsp;throw ex;
 &nbsp;  }
 &nbsp; &nbsp;catch (Throwable ex) {
 &nbsp; &nbsp; &nbsp; &nbsp;failureCause = ex;
 &nbsp; &nbsp; &nbsp; &nbsp;throw new NestedServletException("Request processing failed", ex);
 &nbsp;  }
 &nbsp; &nbsp;finally {
 &nbsp; &nbsp; &nbsp; &nbsp;resetContextHolders(request, previousLocaleContext, previousAttributes);
 &nbsp; &nbsp; &nbsp; &nbsp;if (requestAttributes != null) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;requestAttributes.requestCompleted();
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp;logResult(request, response, failureCause, asyncManager);
 &nbsp; &nbsp; &nbsp; &nbsp;publishRequestHandledEvent(request, response, startTime, failureCause);
 &nbsp;  }
}

②doService()

所在类:org.springframework.web.servlet.DispatcherServlet

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);
 &nbsp; &nbsp;// Keep a snapshot of the request attributes in case of an include,
 &nbsp; &nbsp;// to be able to restore the original attributes after the include.
 &nbsp; &nbsp;Map<String, Object> attributesSnapshot = null;
 &nbsp; &nbsp;if (WebUtils.isIncludeRequest(request)) {
 &nbsp; &nbsp; &nbsp; &nbsp;attributesSnapshot = new HashMap<>();
 &nbsp; &nbsp; &nbsp; &nbsp;Enumeration<?> attrNames = request.getAttributeNames();
 &nbsp; &nbsp; &nbsp; &nbsp;while (attrNames.hasMoreElements()) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String attrName = (String) attrNames.nextElement();
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;attributesSnapshot.put(attrName,request.getAttribute(attrName));
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  }
 &nbsp;  }
 &nbsp; &nbsp;// Make framework objects available to handlers and view objects.
 &nbsp; &nbsp;request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE,getWebApplicationContext());
 &nbsp; &nbsp;request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
 &nbsp; &nbsp;request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
 &nbsp; &nbsp;request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
 &nbsp; &nbsp;if (this.flashMapManager != null) {
 &nbsp; &nbsp; &nbsp; &nbsp;FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request,response);
 &nbsp; &nbsp; &nbsp; &nbsp;if (inputFlashMap != null) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE,Collections.unmodifiableMap(inputFlashMap));
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp;request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
 &nbsp; &nbsp; &nbsp; &nbsp;request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
 &nbsp;  }
 &nbsp; &nbsp;RequestPath requestPath = null;
 &nbsp; &nbsp;if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
 &nbsp; &nbsp; &nbsp; &nbsp;requestPath = ServletRequestPathUtils.parseAndCache(request);
 &nbsp;  }
 &nbsp; &nbsp;try {
 &nbsp; &nbsp; &nbsp; &nbsp;// 处理请求和响应
 &nbsp; &nbsp; &nbsp; &nbsp;doDispatch(request, response);
 &nbsp;  }
 &nbsp; &nbsp;finally {
 &nbsp; &nbsp; &nbsp; &nbsp;if
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Restore the original attribute snapshot, in case of an include.
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (attributesSnapshot != null) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;restoreAttributesAfterInclude(request, attributesSnapshot);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp;if (requestPath != null) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ServletRequestPathUtils.clearParsedRequestPath(request);
 &nbsp; &nbsp; &nbsp;  }
 &nbsp;  }
}

③doDispatch()

所在类:org.springframework.web.servlet.DispatcherServlet

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
 &nbsp; &nbsp;HttpServletRequest processedRequest = request;
 &nbsp; &nbsp;HandlerExecutionChain mappedHandler = null;
 &nbsp; &nbsp;boolean multipartRequestParsed = false;
 &nbsp; &nbsp;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 &nbsp; &nbsp;try {
 &nbsp; &nbsp; &nbsp; &nbsp;ModelAndView mv = null;
 &nbsp; &nbsp; &nbsp; &nbsp;Exception dispatchException = null;
 &nbsp; &nbsp; &nbsp; &nbsp;try {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;processedRequest = checkMultipart(request);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;multipartRequestParsed = (processedRequest != request);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Determine handler for the current request.
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/*
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mappedHandler:调用链
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;包含handler、interceptorList、interceptorIndex
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;handler:浏览器发送的请求所匹配的控制器方法
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;interceptorList:处理控制器方法的所有拦截器集合
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;interceptorIndex:拦截器索引,控制拦截器afterCompletion()的执行
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; */
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mappedHandler = getHandler(processedRequest);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (mappedHandler == null) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;noHandlerFound(processedRequest, response);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Determine handler adapter for the current request.
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 通过控制器方法创建相应的处理器适配器,调用所对应的控制器方法
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Process last-modified header, if supported by the handler.
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;String method = request.getMethod();
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;boolean isGet = "GET".equals(method);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (isGet || "HEAD".equals(method)) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;long lastModified = ha.getLastModified(request,mappedHandler.getHandler());
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (new ServletWebRequest(request,response).checkNotModified(lastModified) && isGet) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 调用拦截器的preHandle()
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (!mappedHandler.applyPreHandle(processedRequest, response)) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Actually invoke the handler.
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 由处理器适配器调用具体的控制器方法,最终获得ModelAndView对象
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mv = ha.handle(processedRequest, response,mappedHandler.getHandler());
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (asyncManager.isConcurrentHandlingStarted()) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;applyDefaultViewName(processedRequest, mv);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 调用拦截器的postHandle()
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mappedHandler.applyPostHandle(processedRequest, response, mv);
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp;catch (Exception ex) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dispatchException = ex;
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp;catch (Throwable err) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// As of 4.3, we're processing Errors thrown from handler methods as well,
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// making them available for @ExceptionHandler methods and otherscenarios.
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dispatchException = new NestedServletException("Handler dispatchfailed", err);
 &nbsp; &nbsp; &nbsp; &nbsp; }
 &nbsp; &nbsp; &nbsp; &nbsp; // 后续处理:处理模型数据和渲染视图
 &nbsp; &nbsp; &nbsp; &nbsp; processDispatchResult(processedRequest, response, mappedHandler, mv,dispatchException);
 &nbsp;  }
 &nbsp; &nbsp;catch (Exception ex) {
 &nbsp; &nbsp; &nbsp; &nbsp;triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
 &nbsp;  }
 &nbsp; &nbsp;catch (Throwable err) {
 &nbsp; &nbsp; &nbsp; &nbsp;triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processingfailed",
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;err));
 &nbsp;  }
 &nbsp; &nbsp;finally {
 &nbsp; &nbsp; &nbsp; &nbsp;if (asyncManager.isConcurrentHandlingStarted()) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Instead of postHandle and afterCompletion
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (mappedHandler != null) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
 &nbsp; &nbsp; &nbsp; &nbsp; }
 &nbsp; &nbsp; &nbsp; &nbsp;else {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Clean up any resources used by a multipart request.
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (multipartRequestParsed) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cleanupMultipart(processedRequest);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp;  }
 &nbsp;  }
} &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;

④processDispatchResult()

private void processDispatchResult(HttpServletRequest request,HttpServletResponse response,@Nullable HandlerExecutionChain
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {
 &nbsp; &nbsp;boolean errorView = false;
 &nbsp; &nbsp;if (exception != null) {
 &nbsp; &nbsp; &nbsp; &nbsp;if (exception instanceof ModelAndViewDefiningException) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;logger.debug("ModelAndViewDefiningException encountered",exception);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mv = ((ModelAndViewDefiningException) exception).getModelAndView();
 &nbsp; &nbsp; &nbsp;  }
 &nbsp; &nbsp; &nbsp; &nbsp;else {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Object handler = (mappedHandler != null ? mappedHandler.getHandler(): null);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mv = processHandlerException(request, response, handler, exception);
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;errorView = (mv != null);
 &nbsp; &nbsp; &nbsp;  }
 &nbsp;  }
 &nbsp; &nbsp;// Did the handler return a view to render?
 &nbsp; &nbsp;if (mv != null && !mv.wasCleared()) {
 &nbsp; &nbsp; &nbsp; &nbsp;// 处理模型数据和渲染视图
 &nbsp; &nbsp; &nbsp; &nbsp;render(mv, request, response);
 &nbsp; &nbsp; &nbsp; &nbsp;if (errorView) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WebUtils.clearErrorRequestAttributes(request);
 &nbsp; &nbsp; &nbsp;  }
 &nbsp;  }
 &nbsp; &nbsp;else {
 &nbsp; &nbsp; &nbsp; &nbsp;if (logger.isTraceEnabled()) {
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;logger.trace("No view rendering, null ModelAndView returned.");
 &nbsp; &nbsp; &nbsp;  }
 &nbsp;  }
 &nbsp; &nbsp;if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
 &nbsp; &nbsp; &nbsp; &nbsp;// Concurrent handling started during a forward
 &nbsp; &nbsp; &nbsp; &nbsp;return;
 &nbsp;  }
 &nbsp; &nbsp;if (mappedHandler != null) {
 &nbsp; &nbsp; &nbsp; &nbsp;// Exception (if any) is already handled..
 &nbsp; &nbsp; &nbsp; &nbsp;// 调用拦截器的afterCompletion()
 &nbsp; &nbsp; &nbsp; &nbsp;mappedHandler.triggerAfterCompletion(request, response, null);
 &nbsp;  }
} &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;

\1) 用户向服务器发送请求,请求被 SpringMVC 前端控制器 DispatcherServlet 捕获。

\2) DispatcherServlet 对请求 URL 进行解析,得到请求资源标识符(URI),判断请求 URI 对应的映射:

a) 不存在

i. 再判断是否配置了 mvc:default-servlet-handler

ii. 如果没配置,则控制台报映射查找不到,客户端展示 404 错误

​​​​

iii. 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示 404

错误

b) 存在则执行下面的流程

\3) 根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及

Handler 对象对应的拦截器),最后以 HandlerExecutionChain 执行链对象的形式返回。

\4) DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter。

\5) 如果成功获得 HandlerAdapter,此时将开始执行拦截器的 preHandler(…)方法【正向】

\6) 提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller)方法,处理请求。

在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:

a) HttpMessageConveter: 将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定

的响应信息

b) 数据转换:对请求消息进行数据转换。如 String 转换成 Integer、Double 等

c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到 BindingResult 或 Error 中

\7) Handler 执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象。

\8) 此时将开始执行拦截器的 postHandle(…)方法【逆向】。

\9) 根据返回的 ModelAndView(此时会判断是否存在异常:如果存在异常,则执行

HandlerExceptionResolver 进行异常处理)选择一个适合的 ViewResolver 进行视图解析,根据 Model

和 View,来渲染视图。

\10) 渲染视图完毕执行拦截器的 afterCompletion(…)方法【逆向】。

\11) 将渲染结果返回给客户端。