天天看點

SpringMVC源碼總結(六)mvc:annotation-driven中的HandlerMethodReturnValueHandler

經過了兩篇的亂碼說明,要重新回到mvc:annotation-driven标簽中,繼續說說HandlerMethodReturnValueHandler的使用,下一篇文章主要說說HttpMessageConverter。 

HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用來處理當含有@RequestMapping的方法排程完成後,後面要進行的事情。 

首先是HandlerMethodReturnValueHandler的自定義注冊: 

mvc:annotation-driven配置如下: 

<a href="http://my.oschina.net/pingpangkuangmo/blog/376341#">?</a>

1

2

3

4

5

<code>&lt;mvc:annotation-driven&gt;</code>

<code>        </code><code>&lt;mvc:</code><code>return</code><code>-value-handlers&gt;</code>

<code>            </code><code>&lt;bean</code><code>class</code><code>=</code><code>"org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler"</code><code>&gt;&lt;/bean&gt;</code>

<code>        </code><code>&lt;/mvc:</code><code>return</code><code>-value-handlers&gt;</code>

<code>    </code><code>&lt;/mvc:annotation-driven&gt;</code>

在啟動AnnotationDrivenBeanDefinitionParser來解析mvc:annotation-driven标簽的過程中(見本系列第三篇部落格),會注冊我們所配置的HandlerMethodReturnValueHandler,如下: 

<code>ManagedList&lt;?&gt; returnValueHandlers = getReturnValueHandlers(element, parserContext);</code>

6

7

<code>private</code> <code>ManagedList&lt;?&gt; getReturnValueHandlers(Element element, ParserContext parserContext) {</code>

<code>        </code><code>Element handlersElement = DomUtils.getChildElementByTagName(element,</code><code>"return-value-handlers"</code><code>);</code>

<code>        </code><code>if</code> <code>(handlersElement !=</code><code>null</code><code>) {</code>

<code>            </code><code>return</code> <code>extractBeanSubElements(handlersElement, parserContext);</code>

<code>        </code><code>}</code>

<code>        </code><code>return</code> <code>null</code><code>;</code>

<code>    </code><code>}</code>

然後将會這些自定義的HandlerMethodReturnValueHandler設定到RequestMappingHandlerAdapter的customReturnValueHandlers屬性中, 

RequestMappingHandlerAdapter的兩個重要屬性: 

customReturnValueHandlers:存放我們自定義的HandlerMethodReturnValueHandler; 

returnValueHandlers:存放最終所有的HandlerMethodReturnValueHandler; 

如下所示: 

8

9

10

11

12

13

<code>public</code> <code>class</code> <code>RequestMappingHandlerAdapter</code><code>extends</code> <code>AbstractHandlerMethodAdapter</code>

<code>        </code><code>implements</code> <code>BeanFactoryAware, InitializingBean {</code>

<code>    </code><code>private</code> <code>List&lt;HandlerMethodArgumentResolver&gt; customArgumentResolvers;</code>

<code>    </code><code>private</code> <code>HandlerMethodArgumentResolverComposite argumentResolvers;</code>

<code>    </code><code>private</code> <code>HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;</code>

<code>//這裡這裡這裡這裡這裡這裡這裡這裡</code>

<code>    </code><code>private</code> <code>List&lt;HandlerMethodReturnValueHandler&gt; customReturnValueHandlers;</code>

<code>    </code><code>private</code> <code>HandlerMethodReturnValueHandlerComposite returnValueHandlers;</code>

returnValueHandlers的屬性類型為HandlerMethodReturnValueHandlerComposite,裡面也有一個list集合,來存放所有的HandlerMethodReturnValueHandler。 

HandlerMethodReturnValueHandlerComposite結構如下: 

<code>public</code> <code>class</code> <code>HandlerMethodReturnValueHandlerComposite</code><code>implements</code> <code>HandlerMethodReturnValueHandler {</code>

<code>    </code><code>protected</code> <code>final</code> <code>Log logger = LogFactory.getLog(getClass());</code>

<code>    </code><code>private</code> <code>final</code> <code>List&lt;HandlerMethodReturnValueHandler&gt; returnValueHandlers =</code>

<code>        </code><code>new</code> <code>ArrayList&lt;HandlerMethodReturnValueHandler&gt;();</code>

<code>    </code><code>/**</code>

在RequestMappingHandlerAdapter建立出來後,會執行afterPropertiesSet()方法,在該方法中會設定所有的HandlerMethodReturnValueHandler到RequestMappingHandlerAdapter的returnValueHandlers屬性中如下: 

14

15

16

17

<code>@Override</code>

<code>    </code><code>public</code> <code>void</code> <code>afterPropertiesSet() {</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.argumentResolvers ==</code><code>null</code><code>) {</code>

<code>            </code><code>List&lt;HandlerMethodArgumentResolver&gt; resolvers = getDefaultArgumentResolvers();</code>

<code>            </code><code>this</code><code>.argumentResolvers =</code><code>new</code> <code>HandlerMethodArgumentResolverComposite().addResolvers(resolvers);</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.initBinderArgumentResolvers ==</code><code>null</code><code>) {</code>

<code>            </code><code>List&lt;HandlerMethodArgumentResolver&gt; resolvers = getDefaultInitBinderArgumentResolvers();</code>

<code>            </code><code>this</code><code>.initBinderArgumentResolvers =</code><code>new</code> <code>HandlerMethodArgumentResolverComposite().addResolvers(resolvers);</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.returnValueHandlers ==</code><code>null</code><code>) {</code>

<code>//擷取所有的HandlerMethodReturnValueHandler</code>

<code>            </code><code>List&lt;HandlerMethodReturnValueHandler&gt; handlers = getDefaultReturnValueHandlers();</code>

<code>            </code><code>this</code><code>.returnValueHandlers =</code><code>new</code> <code>HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);</code>

<code>        </code><code>initControllerAdviceCache();</code>

getDefaultReturnValueHandlers()方法會擷取預設要注冊的和我們自定義的HandlerMethodReturnValueHandler,如下: 

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

<code>private</code> <code>List&lt;HandlerMethodReturnValueHandler&gt; getDefaultReturnValueHandlers() {</code>

<code>        </code><code>List&lt;HandlerMethodReturnValueHandler&gt; handlers =</code><code>new</code> <code>ArrayList&lt;HandlerMethodReturnValueHandler&gt;();</code>

<code>        </code><code>// Single-purpose return value types</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>ModelAndViewMethodReturnValueHandler());</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>ModelMethodProcessor());</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>ViewMethodReturnValueHandler());</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>HttpEntityMethodProcessor(getMessageConverters(),</code><code>this</code><code>.contentNegotiationManager));</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>HttpHeadersReturnValueHandler());</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>CallableMethodReturnValueHandler());</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>DeferredResultMethodReturnValueHandler());</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>AsyncTaskMethodReturnValueHandler(</code><code>this</code><code>.beanFactory));</code>

<code>        </code><code>// Annotation-based return value types</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>ModelAttributeMethodProcessor(</code><code>false</code><code>));</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>RequestResponseBodyMethodProcessor(getMessageConverters(),</code><code>this</code><code>.contentNegotiationManager));</code>

<code>        </code><code>// Multi-purpose return value types</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>ViewNameMethodReturnValueHandler());</code>

<code>        </code><code>handlers.add(</code><code>new</code> <code>MapMethodProcessor());</code>

<code>        </code><code>// Custom return value types</code>

<code>//這裡這裡會從customReturnValueHandlers屬性中擷取我們自定的HandlerMethodReturnValueHandler</code>

<code>        </code><code>if</code> <code>(getCustomReturnValueHandlers() !=</code><code>null</code><code>) {</code>

<code>            </code><code>handlers.addAll(getCustomReturnValueHandlers());</code>

<code>        </code><code>// Catch-all</code>

<code>        </code><code>if</code> <code>(!CollectionUtils.isEmpty(getModelAndViewResolvers())) {</code>

<code>            </code><code>handlers.add(</code><code>new</code> <code>ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));</code>

<code>        </code><code>else</code> <code>{</code>

<code>            </code><code>handlers.add(</code><code>new</code> <code>ModelAttributeMethodProcessor(</code><code>true</code><code>));</code>

<code>        </code><code>return</code> <code>handlers;</code>

至此,所有的HandlerMethodReturnValueHandler的注冊已經完成。我們可以再回顧下,在該系列的第三篇部落格中介紹HandlerMethodReturnValueHandler的使用。 

第一步:擷取合适的HandlerAdapter,當方法含有@RequestMaiing注釋的時候,便選擇RequestMappingHandlerAdapter來進行方法的排程處理 

第二步:方法的排程處理過程為:首先執行方法體,然後根據傳回值來選擇一個合适的HandlerMethodReturnValueHandler,如下代碼: 

<code>public</code> <code>final</code> <code>void</code> <code>invokeAndHandle(ServletWebRequest webRequest,</code>

<code>            </code><code>ModelAndViewContainer mavContainer, Object... providedArgs)</code><code>throws</code> <code>Exception {</code>

<code>        </code><code>Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);</code>

<code>        </code><code>setResponseStatus(webRequest);</code>

<code>        </code><code>if</code> <code>(returnValue ==</code><code>null</code><code>) {</code>

<code>            </code><code>if</code> <code>(isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {</code>

<code>                </code><code>mavContainer.setRequestHandled(</code><code>true</code><code>);</code>

<code>                </code><code>return</code><code>;</code>

<code>            </code><code>}</code>

<code>        </code><code>else</code> <code>if</code> <code>(StringUtils.hasText(</code><code>this</code><code>.responseReason)) {</code>

<code>            </code><code>mavContainer.setRequestHandled(</code><code>true</code><code>);</code>

<code>            </code><code>return</code><code>;</code>

<code>        </code><code>mavContainer.setRequestHandled(</code><code>false</code><code>);</code>

<code>//重點重點重點重點重點重點重點重點重點重點</code>

<code>        </code><code>try</code> <code>{</code>

<code>            </code><code>this</code><code>.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);</code>

<code>        </code><code>catch</code> <code>(Exception ex) {</code>

<code>            </code><code>if</code> <code>(logger.isTraceEnabled()) {</code>

<code>                </code><code>logger.trace(getReturnValueHandlingErrorMessage(</code><code>"Error handling return value"</code><code>, returnValue), ex);</code>

<code>            </code><code>throw</code> <code>ex;</code>

this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest)會周遊所有的已注冊的HandlerMethodReturnValueHandler判斷他們支不支援returnValue的傳回類型。如下: 

<code>public</code> <code>void</code> <code>handleReturnValue(</code>

<code>            </code><code>Object returnValue, MethodParameter returnType,</code>

<code>            </code><code>ModelAndViewContainer mavContainer, NativeWebRequest webRequest)</code>

<code>            </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);</code>

<code>        </code><code>Assert.notNull(handler,</code><code>"Unknown return value type ["</code> <code>+ returnType.getParameterType().getName() +</code><code>"]"</code><code>);</code>

<code>        </code><code>handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);</code>

<code>     </code><code>* Find a registered {@link HandlerMethodReturnValueHandler} that supports the given return type.</code>

<code>     </code><code>*/</code>

<code>    </code><code>private</code> <code>HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {</code>

<code>        </code><code>for</code> <code>(HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {</code>

<code>                </code><code>logger.trace(</code><code>"Testing if return value handler ["</code> <code>+ returnValueHandler +</code><code>"] supports ["</code> <code>+</code>

<code>                        </code><code>returnType.getGenericParameterType() +</code><code>"]"</code><code>);</code>

<code>            </code><code>if</code> <code>(returnValueHandler.supportsReturnType(returnType)) {</code>

<code>                </code><code>return</code> <code>returnValueHandler;</code>

找到支援的HandlerMethodReturnValueHandler後,就要執行它的handleReturnValue方法。 

下面就具體介紹下下常用的這幾個HandlerMethodReturnValueHandler; 

HttpEntityMethodProcessor:用來處理傳回值類型是HttpEntity的方法,簡單用法如下 

<code>@RequestMapping</code><code>(value=</code><code>"/test/httpEntity"</code><code>,method=RequestMethod.GET)</code>

<code>    </code><code>public</code> <code>HttpEntity&lt;String&gt; testHttpEntity()</code><code>throws</code> <code>UnsupportedEncodingException{</code>

<code>        </code><code>String body=</code><code>"中國"</code><code>;</code>

<code>        </code><code>HttpHeaders headers=</code><code>new</code> <code>HttpHeaders();</code>

<code>        </code><code>headers.add(</code><code>"Content-type"</code><code>,</code><code>"text/html;charset=GBK"</code><code>);</code>

<code>        </code><code>HttpEntity&lt;String&gt; ret=</code><code>new</code> <code>HttpEntity&lt;String&gt;(body,headers);</code>

<code>        </code><code>return</code> <code>ret;</code>

就是在建構http協定的傳回體和傳回頭。 

使用案例如,檔案下載下傳。 

經常有人直接用HttpServletRequest和HttpServletResponse來做檔案下載下傳,這種方式便與web容器産生的對象耦合在一起,不推薦使用,而是直接使用spring為我們提供的HttpEntityMethodProcessor這一傳回值處理器,雖然springmvc最終還是用HttpServletResponse來實作,但是這種方式便斷開我們直接與web容器之間的耦合。 

這一過程分析: 

當這個方法執行完成之後,會調用HttpEntityMethodProcessor的handleReturnValue方法, 

該方法内容就是為response設定響應頭,然後将響應體的内容寫入response的body中,此時又會涉及到HttpMessageConverter,當HttpEntity中的body類型為String,又會讓StringHttpMessageConverter來進行轉換。這和@ResponseBody的處理過程是一樣的。 

ViewNameMethodReturnValueHandler:主要用來處理傳回值是String類型(前提不含@ResponseBody标簽),它會将傳回的字元串作為view視圖的名字,如下所示。 

SpringMVC源碼總結(六)mvc:annotation-driven中的HandlerMethodReturnValueHandler

另一種用法,當傳回的字元串以redirect:開始,不再作為view視圖名而是作為重定向的位址,如下: 

<code>@RequestMapping</code><code>(value=</code><code>"/test/string"</code><code>,method=RequestMethod.GET)</code>

<code>    </code><code>public</code> <code>String testString(){</code>

<code>        </code><code>return</code> <code>"redirect:/string"</code><code>;</code>

有了重定向,也有轉發。以forward:開頭便是轉發。 

如下: 

<code>        </code><code>return</code> <code>"forward:/string"</code><code>;</code>

ModelMethodProcessor:用來處理傳回類型為Model的,它預設采用請求路徑作為視圖名稱,如下: 

<code>@RequestMapping</code><code>(value=</code><code>"/test/model"</code><code>,method=RequestMethod.GET)</code>

<code>    </code><code>public</code> <code>Model handleModel(String name)</code><code>throws</code> <code>Exception {</code>

<code>        </code><code>Model model=</code><code>new</code> <code>ExtendedModelMap();</code>

<code>        </code><code>model.addAttribute(</code><code>"name"</code><code>,name);</code>

<code>        </code><code>return</code> <code>model;</code>

SpringMVC源碼總結(六)mvc:annotation-driven中的HandlerMethodReturnValueHandler

ModelAndViewMethodReturnValueHandler:用來處理傳回值類型為ModelAndView,如下: 

<code>@RequestMapping</code><code>(value=</code><code>"/test/modelandview"</code><code>,method=RequestMethod.GET)</code>

<code>    </code><code>public</code> <code>ModelAndView testModelAndView()</code><code>throws</code> <code>Exception {</code>

<code>        </code><code>return</code> <code>new</code> <code>ModelAndView(</code><code>"hello"</code><code>);</code>

RequestResponseBodyMethodProcessor:則是用于處理方法中含有@ResponseBody注解,或類上含有@ResponseBody注解。這一處理過程在本系列的第三篇部落格中有介紹,這裡不再叙述。 

還有其他的HandlerMethodReturnValueHandler,這裡僅僅是作為引路,對HandlerMethodReturnValueHandler有個整體的認識,具體的内容,需要讀者去具體研究。