从DispatcherServlet中的doService了解spring组件之间的处理流程
Posted dearYou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从DispatcherServlet中的doService了解spring组件之间的处理流程相关的知识,希望对你有一定的参考价值。
我了解DispatcherServlet中doService函数的目的是简单了解Spring各个组件之间的关系。
DispatcherServlet的父类FrameworkServlet使用processRequest(request, response)函数来处理逻辑。它对request、response对象进行一些处理后,使用doService函数进行处理。
DispatcherServlet 在doService中设置request的相关属性,然后调用doDispatch
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { this.logRequest(request); Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap(); Enumeration attrNames = request.getAttributeNames(); label95: while(true) { String attrName; do { if (!attrNames.hasMoreElements()) { break label95; } attrName = (String)attrNames.nextElement(); } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet")); attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource()); 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 { this.doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) { this.restoreAttributesAfterInclude(request, attributesSnapshot); } } }
DispatcherServlet的doDispatch做了什么呢?它通过handlerMapping获得Handler,然后生成对应的HandlerAdapter来处理数据逻辑(controller层),获得了一个ModelAndView对象。HandlerAdpater 处理的结果是创建了一个ModelAndView对象,但不代表这个ModelAndView对象中包含了完整的信息。 随后DispatcherServlet使用RequestToViewNameResolver给ModelAndView设置viewName。最后调用processDispatchResult来处理界面逻辑(异常和view层)。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null; Object dispatchException = null; try { processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this.getHandler(processedRequest); if (mappedHandler == null) { this.noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler dispatch failed", var21); } this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); } catch (Exception var22) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22); } catch (Throwable var23) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23)); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if (multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } }
DispatcherServlet的processDispatchResult首先会考虑异常的情况,如果有异常则使用HandlerExceptionResolver来处理异常,随后调用DispatcherServlet的render方法处理界面。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { this.logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException)exception).getModelAndView(); } else { Object handler = mappedHandler != null ? mappedHandler.getHandler() : null; mv = this.processHandlerException(request, response, handler, exception); errorView = mv != null; } } if (mv != null && !mv.wasCleared()) { this.render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else if (this.logger.isTraceEnabled()) { this.logger.trace("No view rendering, null ModelAndView returned."); } if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, (Exception)null); } } }
DispatcherServlet的render方法使用ViewResolver从viewName(ModelAndView中)来得到一个View对象。最后让View对象使用ModelAndView来显示一个界面。
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale(); response.setLocale(locale); String viewName = mv.getViewName(); View view; if (viewName != null) { view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name ‘" + mv.getViewName() + "‘ in servlet with name ‘" + this.getServletName() + "‘"); } } else { view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name ‘" + this.getServletName() + "‘"); } } if (this.logger.isTraceEnabled()) { this.logger.trace("Rendering view [" + view + "] "); } try { if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } view.render(mv.getModelInternal(), request, response); } catch (Exception var8) { if (this.logger.isDebugEnabled()) { this.logger.debug("Error rendering view [" + view + "]", var8); } throw var8; } }
总结下:
几个组件之间的执行流程是 handlerMapping ———》 handlerAdapter————》requestToViewNameResolver ————》handlerExceptionResolver ————》 viewResolver ————》View
以上是关于从DispatcherServlet中的doService了解spring组件之间的处理流程的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Spring WebApplicationContext 中获取 DispatcherServlet?
从DispatcherServlet源码分析SpringMVC处理请求的流程
《SpringMVC从入门到放肆》DispatcherServlet的url-pattern配置详解
ContextLoaderListener和Spring MVC中的DispatcherServlet学习 随手记