日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

面试官:你能告诉我一个请求过来,Spring MVC 是如何找到正确的 Controller 的?

發布時間:2025/3/21 javascript 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试官:你能告诉我一个请求过来,Spring MVC 是如何找到正确的 Controller 的? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

SpringMVC是目前主流的Web MVC框架之一。

我們使用瀏覽器通過地址 http://ip:port/contextPath/path進行訪問,SpringMVC是如何得知用戶到底是訪問哪個Controller中的方法,這期間到底發生了什么。

本文將分析SpringMVC是如何處理請求與Controller之間的映射關系的,讓讀者知道這個過程中到底發生了什么事情。

源碼分析

在分析源碼之前,我們先了解一下幾個東西。

1.這個過程中重要的接口和類。

HandlerMethod類:

Spring3.1版本之后引入的。是一個封裝了方法參數、方法注解,方法返回值等眾多元素的類。

它的子類InvocableHandlerMethod有兩個重要的屬性WebDataBinderFactory和HandlerMethodArgumentResolverComposite, 很明顯是對請求進行處理的。

InvocableHandlerMethod的子類ServletInvocableHandlerMethod有個重要的屬性HandlerMethodReturnValueHandlerComposite,很明顯是對響應進行處理的。

ServletInvocableHandlerMethod這個類在HandlerAdapter對每個請求處理過程中,都會實例化一個出來(上面提到的屬性由HandlerAdapter進行設置),分別對請求和返回進行處理。  (RequestMappingHandlerAdapter源碼,實例化ServletInvocableHandlerMethod的時候分別set了上面提到的重要屬性)

MethodParameter類:

HandlerMethod類中的parameters屬性類型,是一個MethodParameter數組。MethodParameter是一個封裝了方法參數具體信息的工具類,包括參數的的索引位置,類型,注解,參數名等信息。

HandlerMethod在實例化的時候,構造函數中會初始化這個數組,這時只初始化了部分數據,在HandlerAdapter對請求處理過程中會完善其他屬性,之后交予合適的HandlerMethodArgumentResolver接口處理。

以類DeptController為例:

@Controller @RequestMapping(value?=?"/dept") public?class?DeptController?{@Autowiredprivate?IDeptService?deptService;@RequestMapping("/update")@ResponseBodypublic?String?update(Dept?dept)?{deptService.saveOrUpdate(dept);return?"success";}}

(剛初始化時的數據)

(HandlerAdapter處理后的數據)

RequestCondition接口:

Spring3.1版本之后引入的。是SpringMVC的映射基礎中的請求條件,可以進行combine, compareTo,getMatchingCondition操作。這個接口是映射匹配的關鍵接口,其中getMatchingCondition方法關乎是否能找到合適的映射。

RequestMappingInfo類:

Spring3.1版本之后引入的。是一個封裝了各種請求映射條件并實現了RequestCondition接口的類。

有各種RequestCondition實現類屬性,patternsCondition,methodsCondition,paramsCondition,headersCondition,consumesCondition以及producesCondition,這個請求條件看屬性名也了解,分別代表http請求的路徑模式、方法、參數、頭部等信息。

RequestMappingHandlerMapping類:

處理請求與HandlerMethod映射關系的一個類。

2.Web服務器啟動的時候,SpringMVC到底做了什么。

先看AbstractHandlerMethodMapping的initHandlerMethods方法中。

我們進入createRequestMappingInfo方法看下是如何構造RequestMappingInfo對象的。

PatternsRequestCondition構造函數:

類對應的RequestMappingInfo存在的話,跟方法對應的RequestMappingInfo進行combine操作。

然后使用符合條件的method來注冊各種HandlerMethod。

下面我們來看下各種RequestCondition接口的實現類的combine操作。

PatternsRequestCondition:

RequestMethodsRequestCondition:

方法的請求條件,用個set直接add即可。

其他相關的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的獲得(直接看關鍵代碼了):

這里的比較器是使用RequestMappingInfo的compareTo方法(RequestCondition接口定義的)。

然后構造HandlerExecutionChain加上攔截器

實例

寫了這么多,來點例子讓我們驗證一下吧。

@Controller @RequestMapping(value?=?"/wildcard") public?class?TestWildcardController?{@RequestMapping("/test/**")@ResponseBodypublic?String?test1(ModelAndView?view)?{view.setViewName("/test/test");view.addObject("attr",?"TestWildcardController?->?/test/**");return?view;}@RequestMapping("/test/*")@ResponseBodypublic?String?test2(ModelAndView?view)?{view.setViewName("/test/test");view.addObject("attr",?"TestWildcardController?->?/test*");return?view;}@RequestMapping("test?")@ResponseBodypublic?String?test3(ModelAndView?view)?{view.setViewName("/test/test");view.addObject("attr",?"TestWildcardController?->?test?");return?view;}@RequestMapping("test/*")@ResponseBodypublic?String?test4(ModelAndView?view)?{view.setViewName("/test/test");view.addObject("attr",?"TestWildcardController?->?test/*");return?view;}}

由于這里的每個pattern都帶了*因此,都不會加入到urlMap中,但是handlerMethods還是有的。

當我們訪問:http://localhost:8888/SpringMVCDemo/wildcard/test1的時候。

會先根據 "/wildcard/test1" 找urlMap對應的RequestMappingInfo集合,找不到的話取handlerMethods集合中所有的key集合(也就是RequestMappingInfo集合)。

然后進行匹配,匹配根據RequestCondition的getMatchingCondition方法。

最終匹配到2個RequestMappingInfo:

然后會使用比較器進行排序。

之前也分析過,比較器是有優先級的。

我們看到,RequestMappingInfo除了pattern,其他屬性都是一樣的。

我們看下PatternsRequestCondition比較的邏輯:

因此,/test*的通配符比/test?的多,因此,最終選擇了/test?

直接比較優先于通配符。

@Controller @RequestMapping(value?=?"/priority") public?class?TestPriorityController?{@RequestMapping(method?=?RequestMethod.GET)@ResponseBodypublic?String?test1(ModelAndView?view)?{view.setViewName("/test/test");view.addObject("attr",?"其他condition相同,帶有method屬性的優先級高");return?view;}@RequestMapping()@ResponseBodypublic?String?test2(ModelAndView?view)?{view.setViewName("/test/test");view.addObject("attr",?"其他condition相同,不帶method屬性的優先級高");return?view;}}

這里例子,其他requestCondition都一樣,只有RequestMethodCondition不一樣。

看出,方法多的優先級越多。

至于其他的RequestCondition,大家自行查看源碼吧。

資源文件映射

以上分析均是基于Controller方法的映射(RequestMappingHandlerMapping)。

SpringMVC中還有靜態文件的映射,SimpleUrlHandlerMapping。

DispatcherServlet找對應的HandlerExecutionChain的時候會遍歷屬性handlerMappings,這個一個實現了HandlerMapping接口的集合。

由于我們在*-dispatcher.xml中加入了以下配置:

<mvc:resources?location="/static/"?mapping="/static/**"/>

Spring解析配置文件會使用ResourcesBeanDefinitionParser進行解析的時候,會實例化出SimpleUrlHandlerMapping。

其中注冊的HandlerMethod為ResourceHttpRequestHandler。

訪問地址:http://localhost:8888/SpringMVCDemo/static/js/jquery-1.11.0.js

地址匹配到/static/**。

最終SimpleUrlHandlerMapping找到對應的Handler -> ResourceHttpRequestHandler。

ResourceHttpRequestHandler進行handleRequest的時候,直接輸出資源文件的文本內容。

總結

大致上整理了一下SpringMVC對請求的處理,包括其中比較關鍵的類和接口,希望對讀者有幫助。

讓自己對SpringMVC有了更深入的認識,也為之后分析數據綁定,攔截器、HandlerAdapter等打下基礎。

總結

以上是生活随笔為你收集整理的面试官:你能告诉我一个请求过来,Spring MVC 是如何找到正确的 Controller 的?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。