概述 SpringMVC是一种web层的mvc框架,用于替代Servlet,主要用于处理和相应请求,获取表单参数,表单校验。使用SpringMVC可以简化编程。
SpringMVC底层的执行流程 首先通过一张流传广泛的图,来了解一下大致的流程。
从这张图可以看出,整个请求的入口是DispatcherServlet类。之所以请求的入口会是这个类是因为我们在配置springmvc的时候在web.xml中,将所有的请求都交由DispatcherServlet处理了。 请求到达DispatcherServlet类首先由void doService(HttpServletRequest request, HttpServletResponse response)处理的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 protected void doService (HttpServletRequest request, HttpServletResponse response) throws Exception { Map <String, Object> attributesSnapshot = null ; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap <String, Object>(); Enumeration <?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this .cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet" )) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } 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()); 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 { doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { if (attributesSnapshot != null ) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } }
通过对doService方法源码的分析,我们可以知道整个方法所做了三件事情:
快照请求中的属性到attributesSnapshot
将一些组件设置到request中,方便之后使用
处理FlashMap
调用doDispatch(request, response)
doDispatch(request, response) 调用完成后利用attributesSnapshot对request中的属性进行还原
doService还没有真正的进行请求的处理,它所做的事情只是一些准备工作。
下面我们看doDispatch(request, response)到底做了什么事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null ; boolean multipartRequestParsed = false ; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null ; Exception dispatchException = null ; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null ) { noHandlerFound(processedRequest, response); return ; } HandlerAdapter ha = 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 (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } 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 ; } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null ) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
doDispatch的执行步骤大致可以分为三个部分:
根据request找到对应的Handler
根据找到的Handler找到对应的HandlerAdapter
用HandlerAdapter调用Handler处理请求
调用processDispatcheResult方法处理Handler处理之后的结果
这4个步骤内部又完成了许多非常复杂的操作。下面我们就依次解析。
1. doDispatch是如何通过request找到对应的Handler的? 寻找对应的Handler实际上是由mappedHandler = getHandler(processedRequest);完成的。
它的具体实现如下:
1 2 3 4 5 6 7 8 9 protected HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception { for (HandlerMapping hm : this .handlerMappings) { HandlerExecutionChain handler = hm.getHandler(request); if (handler != null ) { return handler; } } return null ; }
去掉了打印日志的代码后,逻辑显得非常的简单。遍历handlerMappings,尝试从每一个HandlerMapping获取handler,一旦拿到就直接返回。 这里又有一个疑问:handlerMappings到底是什么? 它的声明如下:
1 2 private List<HandlerMapping> handlerMappings;
而HandlerMapping其实比较复杂。它的整个架构设计图如下: 它的顶层接口HandlerMapping如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public interface HandlerMapping { String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping" ; String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern" ; String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping" ; String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables" ; String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables" ; String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes" ; HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception; }
简单的讲就是HandlerMapping中的getHandler方法会返回一个HandlerExecutionChain对象,该对象封装了一个Handler处理对象和一些interctptors(拦截器)。 下面是一个HandlerExecutionChain对象的属性:
1 2 3 4 private final Object handler;private HandlerInterceptor[] interceptors;private List<HandlerInterceptor> interceptorList;private int interceptorIndex = -1 ;
2. doDispatch是如何通过Handler找到HandlerAdapter的,以及什么是HandlerAdapter?
实现用Handler获取HandlerAdapter的代码如下:
1 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
它的具体实现如下:
1 2 3 4 5 6 7 8 9 protected HandlerAdapter getHandlerAdapter (Object handler) throws ServletException { for (HandlerAdapter ha : this .handlerAdapters) { if (ha.supports(handler)) { return ha; } } throw new ServletException ("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler" ); }
去掉打印日志的方法后,我们可以发现,这个方法和根据request获取Handler的方法非常的一致。因此我们将重点放在:什么是HandlerAdapter上。HandlerAdapter接口声明如下:
1 2 3 4 5 6 7 8 9 10 11 public interface HandlerAdapter { boolean supports (Object handler) ; ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; long getLastModified (HttpServletRequest request, Object handler) ; }
之所以需要HandlerAdapter,是因为Handler的格式是不固定的,所以处理请求的时候需要HandlerAdapter做适配。
拿到HandlerAdapter,就可做处理请求了。mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 处理请求后就拿到了一个ModelAndView对象。
具体的代码实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Class <?> clazz = ClassUtils.getUserClass(handler); Boolean annotatedWithSessionAttributes = this .sessionAnnotatedClassesCache.get(clazz); if (annotatedWithSessionAttributes == null ) { annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null ); this .sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes); } if (annotatedWithSessionAttributes) { checkAndPrepare(request, response, this .cacheSecondsForSessionAttributeHandlers, true ); } else { checkAndPrepare(request, response, true ); } if (this .synchronizeOnSession) { HttpSession session = request.getSession(false ); if (session != null ) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return invokeHandlerMethod(request, response, handler); } } } return invokeHandlerMethod(request, response, handler); }
最终又来到了invokehandlerMethod方法了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 protected ModelAndView invokeHandlerMethod (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ServletHandlerMethodResolver methodResolver = getMethodResolver(handler); Method handlerMethod = methodResolver.resolveHandlerMethod(request); ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker (methodResolver); ServletWebRequest webRequest = new ServletWebRequest (request, response); ExtendedModelMap implicitModel = new BindingAwareModelMap (); Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest); methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null ), implicitModel, webRequest); return mav; }
最后调用mappedHandler.applyPostHandle(processedRequest, response, mv);进行后处理。后处理的过程就是调用所有的后置拦截器进行处理。