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

  • 相关阅读:
    模板 无源汇上下界可行流 loj115
    ICPC2018JiaozuoE Resistors in Parallel 高精度 数论
    hdu 2255 奔小康赚大钱 最佳匹配 KM算法
    ICPC2018Beijing 现场赛D Frog and Portal 构造
    codeforce 1175E Minimal Segment Cover ST表 倍增思想
    ICPC2018Jiaozuo 现场赛H Can You Solve the Harder Problem? 后缀数组 树上差分 ST表 口胡题解
    luogu P1966 火柴排队 树状数组 逆序对 离散化
    luogu P1970 花匠 贪心
    luogu P1967 货车运输 最大生成树 倍增LCA
    luogu P1315 观光公交 贪心
  • 原文地址:https://www.cnblogs.com/Rozdy/p/4675472.html
Copyright © 2011-2022 走看看