源码深度解析SpringMvc请求运行机制

Posted java微分享

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了源码深度解析SpringMvc请求运行机制相关的知识,希望对你有一定的参考价值。

本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制。通过源码我们可以知道从客户端发送一个URL请求给springMvc开始,到返回数据给客户端期间是怎么运转的。

1、用户请求处理过程:

1、用户发送请求时会先从DispathcherServlerdoService方法开始,在该方法中会将ApplicationContextlocaleResolverthemeResolver等对象添加到request中,紧接着就是调用doDispatch方法:

源码:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  
   if (logger.isDebugEnabled()) {  
       String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";  
       logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +  
               " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");  
   }  
   // Keep a snapshot of the request attributes in case of an include,  
   // to be able to restore the original attributes after the include.  
   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));  
           }  
       }  
   }  
   // Make framework objects available to handlers and view objects.  
     <strong>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());</strong>  
   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 {  
       <strong>doDispatch(request, response);</strong>  
   }  
   finally {  
       if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  
           return;  
       }  
       // Restore the original attribute snapshot, in case of an include.  
       if (attributesSnapshot != null) {  
           restoreAttributesAfterInclude(request, attributesSnapshot);  
       }  
   }  
}  

doDispatch方法就是处理用户请求的方法。


2、进入该方法后首先会检查该请求是否是文件上传的请求(校验的规则是是否是post并且contenttType是否为multipart/为前缀)即调用的是checkMultipart方法;如果是的将request包装成MultipartHttpServletRequest。见源码:

doDispatch:

    processedRequest = checkMultipart(request);  


checkMultipart:

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {  
       if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {  
           if (request instanceof MultipartHttpServletRequest) {  
               logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +  
                       "this typically results from an additional MultipartFilter in web.xml");  
           }  
           else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) {  
               logger.debug("Multipart resolution failed for current request before - " +  
                       "skipping re-resolution for undisturbed error rendering");  
           }  
           else {  
               return this.multipartResolver.resolveMultipart(request);  
           }  
       }  
       // If not returned before: return original request.  
       return request;  
   }

3、然后调用getHandler方法来匹配每个HandlerMapping对象,如果匹配成功会返回这个Handle的处理链HandlerExecutionChain对象,在获取该对象的内部其实也获取我们自定定义的拦截器,并执行了其中的方法

见源码:

doDispatch

HandlerExecutionChain mappedHandler = null;  
mappedHandler = getHandler(processedRequest);  

getHandler方法:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
       for (HandlerMapping hm : this.handlerMappings) {  
           if (logger.isTraceEnabled()) {  
               logger.trace(  
                       "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");  
           }  
           HandlerExecutionChain handler = hm.getHandler(request);  
           if (handler != null) {  
               return handler;  
           }  
       }  
       return null;  
   }  
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
   Object handler = getHandlerInternal(request);  
   if (handler == null) {  
       handler = getDefaultHandler();  
   }  
   if (handler == null) {  
       return null;  
   }  
   // Bean name or resolved handler?  
   if (handler instanceof String) {  
       String handlerName = (String) handler;  
       handler = getApplicationContext().getBean(handlerName);  
   }  
   return getHandlerExecutionChain(handler, request);  
}  


getHandlerExecutionChain:

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {  
       HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?  
               (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));  
       chain.addInterceptors(getAdaptedInterceptors());  
       String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);  
       for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {  
           if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {  
               chain.addInterceptor(mappedInterceptor.getInterceptor());  
           }  
       }  
       return chain;  
   }  


4、执行拦截器的preHandle方法,如果返回false执行afterCompletion方法并理解返回

5、通过上述获取到了HandlerExecutionChain对象,通过该对象的getHandler()方法获得一个object通过HandlerAdapter进行封装得到HandlerAdapter对象

6、该对象调用handle方法来执行Controller中的方法,该对象如果返回一个ModelAndView给DispatcherServlet

7、DispatcherServlet借助ViewResolver完成逻辑试图名到真实视图对象的解析,得到View后DispatcherServlet使用这个View对ModelAndView中的模型数据进行视图渲染




以上是关于源码深度解析SpringMvc请求运行机制的主要内容,如果未能解决你的问题,请参考以下文章

源码分析spring-mvc启动流程

详解Spring mvc工作原理及源码分析

Flink 源码解析 —— 深度解析 Flink 序列化机制

Spring源码学习笔记

Spring MVC注解Controller源码流程解析---请求匹配中的容错处理

spring源码学习之springMVC