zoukankan      html  css  js  c++  java
  • 源码深度解析SpringMvc请求运行机制(转)

     

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

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

    1、用户请求处理过程:

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

    源码:

    1. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  
    2.     if (logger.isDebugEnabled()) {  
    3.         String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";  
    4.         logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +  
    5.                 " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");  
    6.     }  
    7.   
    8.     // Keep a snapshot of the request attributes in case of an include,  
    9.     // to be able to restore the original attributes after the include.  
    10.     Map<String, Object> attributesSnapshot = null;  
    11.     if (WebUtils.isIncludeRequest(request)) {  
    12.         attributesSnapshot = new HashMap<String, Object>();  
    13.         Enumeration<?> attrNames = request.getAttributeNames();  
    14.         while (attrNames.hasMoreElements()) {  
    15.             String attrName = (String) attrNames.nextElement();  
    16.             if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {  
    17.                 attributesSnapshot.put(attrName, request.getAttribute(attrName));  
    18.             }  
    19.         }  
    20.     }  
    21.   
    22.     // Make framework objects available to handlers and view objects.  
    23.       <strong>request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());  
    24.     request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);  
    25.     request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);  
    26.     request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());</strong>  
    27.   
    28.     FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);  
    29.     if (inputFlashMap != null) {  
    30.         request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));  
    31.     }  
    32.     request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());  
    33.     request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);  
    34.   
    35.     try {  
    36.         <strong>doDispatch(request, response);</strong>  
    37.     }  
    38.     finally {  
    39.         if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  
    40.             return;  
    41.         }  
    42.         // Restore the original attribute snapshot, in case of an include.  
    43.         if (attributesSnapshot != null) {  
    44.             restoreAttributesAfterInclude(request, attributesSnapshot);  
    45.         }  
    46.     }  
    47. }  

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

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

    doDispatch:

    1. processedRequest = checkMultipart(request);  
    checkMultipart:
    1. protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {  
    2.         if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {  
    3.             if (request instanceof MultipartHttpServletRequest) {  
    4.                 logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +  
    5.                         "this typically results from an additional MultipartFilter in web.xml");  
    6.             }  
    7.             else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) {  
    8.                 logger.debug("Multipart resolution failed for current request before - " +  
    9.                         "skipping re-resolution for undisturbed error rendering");  
    10.             }  
    11.             else {  
    12.                 return this.multipartResolver.resolveMultipart(request);  
    13.             }  
    14.         }  
    15.         // If not returned before: return original request.  
    16.         return request;  
    17.     }  
    3、然后调用getHandler方法来匹配每个HandlerMapping对象,如果匹配成功会返回这个Handle的处理链HandlerExecutionChain对象,在获取该对象的内部其实也获取我们自定定义的拦截器,并执行了其中的方法

    见源码:

    doDispatch: 

    1. HandlerExecutionChain mappedHandler = null;  
    2. mappedHandler = getHandler(processedRequest);  
    getHandler方法:
    1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
    2.         for (HandlerMapping hm : this.handlerMappings) {  
    3.             if (logger.isTraceEnabled()) {  
    4.                 logger.trace(  
    5.                         "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");  
    6.             }  
    7.             HandlerExecutionChain handler = hm.getHandler(request);  
    8.             if (handler != null) {  
    9.                 return handler;  
    10.             }  
    11.         }  
    12.         return null;  
    13.     }  
    1. hm.getHandler方法:  
    1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
    2.     Object handler = getHandlerInternal(request);  
    3.     if (handler == null) {  
    4.         handler = getDefaultHandler();  
    5.     }  
    6.     if (handler == null) {  
    7.         return null;  
    8.     }  
    9.     // Bean name or resolved handler?  
    10.     if (handler instanceof String) {  
    11.         String handlerName = (String) handler;  
    12.         handler = getApplicationContext().getBean(handlerName);  
    13.     }  
    14.     return getHandlerExecutionChain(handler, request);  
    15. }  
    getHandlerExecutionChain:
    1. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {  
    2.         HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?  
    3.                 (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));  
    4.         chain.addInterceptors(getAdaptedInterceptors());  
    5.   
    6.         String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);  
    7.         for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {  
    8.             if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {  
    9.                 chain.addInterceptor(mappedInterceptor.getInterceptor());  
    10.             }  
    11.         }  
    12.   
    13.         return chain;  
    14.     }  
    4、执行拦截器的preHandle方法,如果返回false执行afterCompletion方法并理解返回

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

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

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

    本文转自:http://blog.csdn.net/liyantianmin/article/details/46948963

  • 相关阅读:
    Thread之六:线程创建方法
    MySQL优化技巧之四(数据库设计中的一些技巧)
    数据库设计三大范式
    分布式事务之:TCC (Try-Confirm-Cancel) 模式
    spring AOP 之五:Spring MVC通过AOP切面编程来拦截controller
    Thread之五:线程的优先级
    分布式事务之:TCC几个框架的测试情况记录
    spring AOP 之四:@AspectJ切入点标识符语法详解
    IP地址漂移的实现与原理
    高可用集群heartbeat全攻略
  • 原文地址:https://www.cnblogs.com/Rozdy/p/4675472.html
Copyright © 2011-2022 走看看