<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 前言 我們使用瀏覽器通過地址 http://ip:port/contextPath/path 進行訪問,SpringMVC是如何得知用戶到底是訪問哪個Controller中的方法,這期間到底發生了什么。 本章將分析SpringMVC是如何處理請求與Controller之間的映射關系的,讓讀者知道這個過程中到底發生了什么事情。 # 源碼分析 在分析源碼之前,我們先了解一下幾個東西。 1.這個過程中重要的接口和類。 **HandlerMethod**類: Spring3.1版本之后引入的。 是一個封裝了方法參數、方法注解,方法返回值等眾多元素的類。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping01.jpg) 它的子類InvocableHandlerMethod有兩個重要的屬性WebDataBinderFactory和HandlerMethodArgumentResolverComposite,很明顯是對請求進行處理的。 InvocableHandlerMethod的子類ServletInvocableHandlerMethod有個重要的屬性HandlerMethodReturnValueHandlerComposite,很明顯是對響應進行處理的。 ServletInvocableHandlerMethod這個類在HandlerAdapter對每個請求處理過程中,都會實例化一個出來(上面提到的屬性由HandlerAdapter進行設置),分別對請求和返回進行處理。(RequestMappingHandlerAdapter源碼,實例化ServletInvocableHandlerMethod的時候分別set了上面提到的重要屬性) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping02.png) **MethodParameter**類: HandlerMethod類中的parameters屬性類型,是一個MethodParameter數組。MethodParameter是一個封裝了方法參數具體信息的工具類,包括參數的的索引位置,類型,注解,參數名等信息。 HandlerMethod在實例化的時候,構造函數中會初始化這個數組,這時只初始化了部分數據,在HandlerAdapter對請求處理過程中會完善其他屬性,之后交予合適的HandlerMethodArgumentResolver接口處理。 以類DeptController為例: @Controller @RequestMapping(value = "/dept") public class DeptController { @Autowired private IDeptService deptService; @RequestMapping("/update") @ResponseBody public String update(Dept dept) { deptService.saveOrUpdate(dept); return "success"; } } (剛初始化時的數據)   ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping03.png) (HandlerAdapter處理后的數據) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping04.png) **RequestCondition**接口: Spring3.1版本之后引入的。 **是SpringMVC的映射基礎中的請求條件,可以進行combine,compareTo,getMatchingCondition操作。這個接口是映射匹配的關鍵接口,其中getMatchingCondition方法關乎是否能找到合適的映射。** ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping05.png) **RequestMappingInfo類**: Spring3.1版本之后引入的。 是一個封裝了各種請求映射條件并實現了RequestCondition接口的類。 有各種RequestCondition實現類屬性,patternsCondition,methodsCondition,paramsCondition,headersCondition,consumesCondition以及producesCondition,這個請求條件看屬性名也了解,分別代表http請求的路徑模式、方法、參數、頭部等信息。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping06.png) **RequestMappingHandlerMapping類**: 處理請求與HandlerMethod映射關系的一個類。 2.Web服務器啟動的時候,SpringMVC到底做了什么。 先看AbstractHandlerMethodMapping的initHandlerMethods方法中。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping07.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping08.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping09.png) 我們進入createRequestMappingInfo方法看下是如何構造RequestMappingInfo對象的。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping10.png) PatternsRequestCondition構造函數: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping11.png) 類對應的RequestMappingInfo存在的話,跟方法對應的RequestMappingInfo進行combine操作。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping12.png) 然后使用符合條件的method來注冊各種HandlerMethod。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping13.png) 下面我們來看下各種RequestCondition接口的實現類的combine操作。 PatternsRequestCondition: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping14.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping15.png) RequestMethodsRequestCondition: 方法的請求條件,用個set直接add即可。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping16.png) 其他相關的RequestConditon實現類讀者可自行查看源碼。 最終,RequestMappingHandlerMapping中兩個比較重要的屬性 private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>(); private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>(); T為RequestMappingInfo。 構造完成。 我們知道,SpringMVC的分發器DispatcherServlet會根據瀏覽器的請求地址獲得HandlerExecutionChain。 這個過程我們看是如何實現的。 首先看HandlerMethod的獲得(直接看關鍵代碼了): ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping17.png) 這里的比較器是使用RequestMappingInfo的compareTo方法(RequestCondition接口定義的)。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping18.png) 然后構造HandlerExecutionChain加上攔截器 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping19.png) # 實例 寫了這么多,來點例子讓我們驗證一下吧。 @Controller @RequestMapping(value = "/wildcard") public class TestWildcardController { @RequestMapping("/test/**") @ResponseBody public String test1(ModelAndView view) { view.setViewName("/test/test"); view.addObject("attr", "TestWildcardController -> /test/**"); return view; } @RequestMapping("/test/*") @ResponseBody public String test2(ModelAndView view) { view.setViewName("/test/test"); view.addObject("attr", "TestWildcardController -> /test*"); return view; } @RequestMapping("test?") @ResponseBody public String test3(ModelAndView view) { view.setViewName("/test/test"); view.addObject("attr", "TestWildcardController -> test?"); return view; } @RequestMapping("test/*") @ResponseBody public String test4(ModelAndView view) { view.setViewName("/test/test"); view.addObject("attr", "TestWildcardController -> test/*"); return view; } } 由于這里的每個pattern都帶了*因此,都不會加入到urlMap中,但是handlerMethods還是有的。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping20.png) 當我們訪問:http://localhost:8888/SpringMVCDemo/wildcard/test1 的時候。 會先根據 "/wildcard/test1"找urlMap對應的RequestMappingInfo集合,找不到的話取handlerMethods集合中所有的key集合(也就是RequestMappingInfo集合)。 然后進行匹配,匹配根據RequestCondition的getMatchingCondition方法。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping21.png) 最終匹配到2個RequestMappingInfo: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping22.png) 然后會使用比較器進行排序。 之前也分析過,比較器是有優先級的。 我們看到,RequestMappingInfo除了pattern,其他屬性都是一樣的。 我們看下PatternsRequestCondition比較的邏輯: ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping23.png) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping24.png) 因此,/test*的通配符比/test?的多,因此,最終選擇了/test? ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping25.png) 直接比較優先于通配符。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping26.png) @Controller @RequestMapping(value = "/priority") public class TestPriorityController { @RequestMapping(method = RequestMethod.GET) @ResponseBody public String test1(ModelAndView view) { view.setViewName("/test/test"); view.addObject("attr", "其他condition相同,帶有method屬性的優先級高"); return view; } @RequestMapping() @ResponseBody public String test2(ModelAndView view) { view.setViewName("/test/test"); view.addObject("attr", "其他condition相同,不帶method屬性的優先級高"); return view; } } 這里例子,其他requestCondition都一樣,只有RequestMethodCondition不一樣。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping27.png) 看出,方法多的優先級越多。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping28.png) 至于其他的RequestCondition,大家自行查看源碼吧。 # 資源文件映射 以上分析均是基于Controller方法的映射(RequestMappingHandlerMapping)。 SpringMVC中還有靜態文件的映射,SimpleUrlHandlerMapping。 DispatcherServlet找對應的HandlerExecutionChain的時候會遍歷屬性handlerMappings,這個一個實現了HandlerMapping接口的集合。 由于我們在*-dispatcher.xml中加入了以下配置: <mvc:resources location="/static/" mapping="/static/**"/> Spring解析配置文件會使用ResourcesBeanDefinitionParser進行解析的時候,會實例化出SimpleUrlHandlerMapping。 ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping29.jpg) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping30.jpg) 其中注冊的HandlerMethod為ResourceHttpRequestHandler。 訪問地址:http://localhost:8888/SpringMVCDemo/static/js/jquery-1.11.0.js ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping31.jpg) ![](http://7x2wh6.com1.z0.glb.clouddn.com/springmvc-request-mapping32.jpg) 地址匹配到/static/**。 最終SimpleUrlHandlerMapping找到對應的Handler -> ResourceHttpRequestHandler。 ResourceHttpRequestHandler進行handleRequest的時候,直接輸出資源文件的文本內容。 # 總結 大致上整理了一下SpringMVC對請求的處理,包括其中比較關鍵的類和接口,希望對讀者有幫助。 也讓讀者對SpringMVC有了更深入的認識,也為之后分析數據綁定,攔截器、HandlerAdapter等打下基礎。 # 參考資料 [http://jinnianshilongnian.iteye.com/blog/1684403](http://jinnianshilongnian.iteye.com/blog/1684403) [http://my.oschina.net/HeliosFly/blog/212329](http://my.oschina.net/HeliosFly/blog/212329)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看