SpringMVC源碼解析,springmvc源碼
HandlerMethodArgumentResolver主要負責執行handler前參數準備工作.
看個例子,紅色部分的id初始化,填儲值就是它乾的活:
1 @RequestMapping(value = "/{id}")2 @ResponseBody3 public String getBook(@PathVariable("id") String id) {4 Hello helloProxy = new HelloProxy();5 helloProxy.say("Jack");6 7 return id;8 }
分析目錄:
1. 介面定義(是否支援參數,處理參數)
2. 代言人HandlerMethodArgumentResolverComposite,封裝其他實現
3. 具體實現
composite除外,根據是否實現HandlerMethodReturnValueHandle分為XXXMethodArgumentResolver(不實現)和XXXMethodProssor(實現)
HandlerMethodReturnValueHandle用於處理傳回值.
實作類別實在太多,簡單分析下各類的職責吧,具體內容看下面.
1. 介面定義
老規矩,上來先看介面,看似很簡單,一個是否支援,一個處理.
1 package org.springframework.web.method.support; 2 public interface HandlerMethodArgumentResolver { 3 4 /** 5 * 解析器是否支援參數 6 */ 7 boolean supportsParameter(MethodParameter parameter); 8 9 /**10 * 解析參數,填充到參數值11 */12 Object resolveArgument(MethodParameter parameter,13 ModelAndViewContainer mavContainer,14 NativeWebRequest webRequest,15 WebDataBinderFactory binderFactory) throws Exception;16 17 }
2. 代言人HandlerMethodArgumentResolverComposite,封裝其他實現
通過封裝其他的實現,對外統一提供解析服務,這樣使用者在使用時,根本不用關心參數在哪裡怎麼解析處理的,只需要調用supportsParameter,resolveArgument就可以了.
而如果要擴充支援的類型也很簡單,添加實作類別,然後通過addResolver註冊進來就可以了.
看到這個怎麼想起設計模式的開閉原則了.對擴充開放,對修改關閉.
看點代碼:
封裝其他實現,並提供註冊功能
1 package org.springframework.web.method.support; 2 public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver { 3 private final List<HandlerMethodArgumentResolver> argumentResolvers = 4 new LinkedList<HandlerMethodArgumentResolver>(); 5 public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver argumentResolver) { 6 this.argumentResolvers.add(argumentResolver); 7 return this; 8 } 9 10 public HandlerMethodArgumentResolverComposite addResolvers(11 List<? extends HandlerMethodArgumentResolver> argumentResolvers) {12 if (argumentResolvers != null) {13 for (HandlerMethodArgumentResolver resolver : argumentResolvers) {14 this.argumentResolvers.add(resolver); // 難得沒調addResolver15 }16 }17 return this;18 }
在來看看具體是如何處理請求的:
都是都通過private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter)尋找resolver實現的.
先用parameter當key去緩衝中取
如果取不到迭代所有的reoslevers,一個個執行supportsParameter,直到有一個true.
跟GOF的責任鏈設計模式定義一致.
1 package org.springframework.web.method.support; 2 public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver { 3 public boolean supportsParameter(MethodParameter parameter) { 4 return getArgumentResolver(parameter) != null; 5 } 6 public Object resolveArgument( 7 MethodParameter parameter, ModelAndViewContainer mavContainer, 8 NativeWebRequest webRequest, WebDataBinderFactory binderFactory) 9 throws Exception {10 11 HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);12 return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);13 }14 private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {15 HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);16 if (result == null) {17 for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {18 if (methodArgumentResolver.supportsParameter(parameter)) {19 result = methodArgumentResolver;20 this.argumentResolverCache.put(parameter, result);21 break;22 }23 }24 }25 return result;26 }27 }
3. 具體實現
實在太多了,先湊合看下各個類的職責吧,具體的分析後續在debug中做.
AbstractMessageConverterMethodArgumentResolver 使用HttpMessageConverter解析來自request body參數值的基類.
--AbstractMessageConverterMethodProcessor 添加傳回值處理,所以改名了
----HttpEntityMethodProcessor 解析參數時,只處理HttpEntity;處理傳回值時支援HttpEntity和ResponseEntity.
----RequestResponseBodyMethodProcessor 使用HttpMessageConverter解析@RequestBody參數;處理使用@ResponseBody的傳回值
--RequestPartMethodArgumentResolver 解析使用@RequestPart,@RequestParam註解的參數;MultipartFile和Part的子類參數
AbstractNamedValueMethodArgumentResolver 解析named vlaue型別參數(其實就是索引值對).
--AbstractCookieValueMethodArgumentResolver 解析使用@CookieValue註解的參數
----ServletCookieValueMethodArgumentResolver 從HttpServletRequest中解析出cookie值
--ExpressionValueMethodArgumentResolver 解析@Value註解的參數
--MatrixVariableMethodArgumentResolver 解析@MatrixVariable註解的參數,不包括map類型
--PathVariableMethodArgumentResolver 解析使用@PathVariable註解的參數,從uri中解析參數
--RequestHeaderMethodArgumentResolver 解析使用@RequestHeader註解的參數,不包括map類型
--RequestParamMethodArgumentResolver 解析從request流中擷取值的參數,如@RequestParam,MultipartFile,Part,預設使用時解析基本參數.
AbstractWebArgumentResolverAdapter 使用@WebArgumentResolver的基類,用於向後相容.適配WebArgumentResolver
--ServletWebArgumentResolverAdapter 建立NativeWebRequest--
ErrorsMethodArgumentResolver 處理Errors子類參數
MapMethodProcessor 處理map型別參數
MatrixVariableMapMethodArgumentResolver 使用@MatrixVariable註解的map型別參數
ModelAttributeMethodProcessor 解析使用@ModelAttribute註解參數
--ServletModelAttributeMethodProcessor 使用ServletRequestDataBinder解析參數
ModelMethodProcessor 處理model型別參數
PathVariableMapMethodArgumentResolver 處理使用@PathVariable註解的map參數
RedirectAttributesMethodArgumentResolver 處理RedirectAttributes型別參數
RequestHeaderMapMethodArgumentResolver 處理使用@RequestHeader註解的map參數
RequestParamMapMethodArgumentResolver 處理使用@RequestParam註解的map參數
ServletRequestMethodArgumentResolver 處理request相關的參數:WebRequest,ServletRequest,MultipartRequest,HttpSession,Principal,Locale,InputStream,Reader
ServletResponseMethodArgumentResolver 解析response相關的參數:ServletResponse,OutputStream,Writer
SessionStatusMethodArgumentResolver 處理SessionStatus型別參數
UriComponentsBuilderMethodArgumentResolver 處理UriComponentsBuilder型別參數