HandlerMethodArgumentResolver主要負責執行handler前參數准備工作.
看個例子,紅色部分的id初始化,填充值就是它干的活:
1 @RequestMapping(value = "/{id}") 2 @ResponseBody 3 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); // 難得沒調addResolver 15 } 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類型參數
