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

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

HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用來處理當含有@RequestMapping的方法調度完成後,後面要進行的事情。 
首先是HandlerMethodReturnValueHandler的自定義註冊: 
mvc:annotation-driven配置如下:
 
Java代碼  收藏代碼
  1. <mvc:annotation-driven>  
  2.         <mvc:return-value-handlers>  
  3.             <bean class="org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler"></bean>  
  4.         </mvc:return-value-handlers>  
  5.     </mvc:annotation-driven>  

在啓動AnnotationDrivenBeanDefinitionParser來解析mvc:annotation-driven標籤的過程中(見本系列第三篇博客),會註冊我們所配置的HandlerMethodReturnValueHandler,如下: 
Java代碼  收藏代碼
  1. ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);  

Java代碼  收藏代碼
  1. private ManagedList<?> getReturnValueHandlers(Element element, ParserContext parserContext) {  
  2.         Element handlersElement = DomUtils.getChildElementByTagName(element, "return-value-handlers");  
  3.         if (handlersElement != null) {  
  4.             return extractBeanSubElements(handlersElement, parserContext);  
  5.         }  
  6.         return null;  
  7.     }  

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

RequestMappingHandlerAdapter的兩個重要屬性: 
customReturnValueHandlers:存放我們自定義的HandlerMethodReturnValueHandler; 
returnValueHandlers:存放最終所有的HandlerMethodReturnValueHandler; 
如下所示:
 
Java代碼  收藏代碼
  1. public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter  
  2.         implements BeanFactoryAware, InitializingBean {  
  3.   
  4.     private List<HandlerMethodArgumentResolver> customArgumentResolvers;  
  5.   
  6.     private HandlerMethodArgumentResolverComposite argumentResolvers;  
  7.   
  8.     private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;  
  9.   
  10. //這裏這裏這裏這裏這裏這裏這裏這裏  
  11.     private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;  
  12. //這裏這裏這裏這裏這裏這裏這裏這裏  
  13.     private HandlerMethodReturnValueHandlerComposite returnValueHandlers;  

returnValueHandlers的屬性類型爲HandlerMethodReturnValueHandlerComposite,裏面也有一個list集合,來存放所有的HandlerMethodReturnValueHandler。 
HandlerMethodReturnValueHandlerComposite結構如下:
 
Java代碼  收藏代碼
  1. public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {  
  2.   
  3.     protected final Log logger = LogFactory.getLog(getClass());  
  4.   
  5.     private final List<HandlerMethodReturnValueHandler> returnValueHandlers =  
  6.         new ArrayList<HandlerMethodReturnValueHandler>();  
  7.   
  8.     /**  

在RequestMappingHandlerAdapter創建出來後,會執行afterPropertiesSet()方法,在該方法中會設置所有的HandlerMethodReturnValueHandler到RequestMappingHandlerAdapter的returnValueHandlers屬性中如下: 
Java代碼  收藏代碼
  1. @Override  
  2.     public void afterPropertiesSet() {  
  3.         if (this.argumentResolvers == null) {  
  4.             List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();  
  5.             this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);  
  6.         }  
  7.         if (this.initBinderArgumentResolvers == null) {  
  8.             List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();  
  9.             this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);  
  10.         }  
  11.         if (this.returnValueHandlers == null) {  
  12. //獲取所有的HandlerMethodReturnValueHandler  
  13.             List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();  
  14.             this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);  
  15.         }  
  16.         initControllerAdviceCache();  
  17.     }  

getDefaultReturnValueHandlers()方法會獲取默認要註冊的和我們自定義的HandlerMethodReturnValueHandler,如下: 
Java代碼  收藏代碼
  1. private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {  
  2.         List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();  
  3.   
  4.         // Single-purpose return value types  
  5.         handlers.add(new ModelAndViewMethodReturnValueHandler());  
  6.         handlers.add(new ModelMethodProcessor());  
  7.         handlers.add(new ViewMethodReturnValueHandler());  
  8.         handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));  
  9.         handlers.add(new HttpHeadersReturnValueHandler());  
  10.         handlers.add(new CallableMethodReturnValueHandler());  
  11.         handlers.add(new DeferredResultMethodReturnValueHandler());  
  12.         handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));  
  13.   
  14.         // Annotation-based return value types  
  15.         handlers.add(new ModelAttributeMethodProcessor(false));  
  16.         handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));  
  17.   
  18.         // Multi-purpose return value types  
  19.         handlers.add(new ViewNameMethodReturnValueHandler());  
  20.         handlers.add(new MapMethodProcessor());  
  21.   
  22.         // Custom return value types  
  23. //這裏這裏會從customReturnValueHandlers屬性中獲取我們自定的HandlerMethodReturnValueHandler  
  24.         if (getCustomReturnValueHandlers() != null) {  
  25.             handlers.addAll(getCustomReturnValueHandlers());  
  26.         }  
  27.   
  28.         // Catch-all  
  29.         if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {  
  30.             handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));  
  31.         }  
  32.         else {  
  33.             handlers.add(new ModelAttributeMethodProcessor(true));  
  34.         }  
  35.   
  36.         return handlers;  
  37.     }  

至此,所有的HandlerMethodReturnValueHandler的註冊已經完成。我們可以再回顧下,在該系列的第三篇博客中介紹HandlerMethodReturnValueHandler的使用。 
第一步:獲取合適的HandlerAdapter,當方法含有@RequestMaiing註釋的時候,便選擇RequestMappingHandlerAdapter來進行方法的調度處理 
第二步:方法的調度處理過程爲:首先執行方法體,然後根據返回值來選擇一個合適的HandlerMethodReturnValueHandler,如下代碼:
 
Java代碼  收藏代碼
  1. public final void invokeAndHandle(ServletWebRequest webRequest,  
  2.             ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {  
  3.   
  4.         Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);  
  5.   
  6.         setResponseStatus(webRequest);  
  7.   
  8.         if (returnValue == null) {  
  9.             if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {  
  10.                 mavContainer.setRequestHandled(true);  
  11.                 return;  
  12.             }  
  13.         }  
  14.         else if (StringUtils.hasText(this.responseReason)) {  
  15.             mavContainer.setRequestHandled(true);  
  16.             return;  
  17.         }  
  18.   
  19.         mavContainer.setRequestHandled(false);  
  20. //重點重點重點重點重點重點重點重點重點重點  
  21.         try {  
  22.             this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);  
  23.         }  
  24.         catch (Exception ex) {  
  25.             if (logger.isTraceEnabled()) {  
  26.                 logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);  
  27.             }  
  28.             throw ex;  
  29.         }  
  30.     }  

this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest)會遍歷所有的已註冊的HandlerMethodReturnValueHandler判斷他們支不支持returnValue的返回類型。如下: 
Java代碼  收藏代碼
  1. public void handleReturnValue(  
  2.             Object returnValue, MethodParameter returnType,  
  3.             ModelAndViewContainer mavContainer, NativeWebRequest webRequest)  
  4.             throws Exception {  
  5.   
  6.         HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);  
  7.         Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");  
  8.         handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);  
  9.     }  
  10.   
  11.     /** 
  12.      * Find a registered {@link HandlerMethodReturnValueHandler} that supports the given return type. 
  13.      */  
  14.     private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {  
  15.         for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {  
  16.             if (logger.isTraceEnabled()) {  
  17.                 logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" +  
  18.                         returnType.getGenericParameterType() + "]");  
  19.             }  
  20.             if (returnValueHandler.supportsReturnType(returnType)) {  
  21.                 return returnValueHandler;  
  22.             }  
  23.         }  
  24.         return null;  
  25.     }  

找到支持的HandlerMethodReturnValueHandler後,就要執行它的handleReturnValue方法。 
下面就具體介紹下下常用的這幾個HandlerMethodReturnValueHandler; 
HttpEntityMethodProcessor:用來處理返回值類型是HttpEntity的方法,簡單用法如下
 
Java代碼  收藏代碼
  1. @RequestMapping(value="/test/httpEntity",method=RequestMethod.GET)  
  2.     public HttpEntity<String> testHttpEntity() throws UnsupportedEncodingException{  
  3.         String body="中國";  
  4.         HttpHeaders headers=new HttpHeaders();  
  5.         headers.add("Content-type","text/html;charset=GBK");  
  6.         HttpEntity<String> ret=new HttpEntity<String>(body,headers);  
  7.         return ret;  
  8.     }  

就是在構建http協議的返回體和返回頭。 

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

這一過程分析: 
當這個方法執行完成之後,會調用HttpEntityMethodProcessor的handleReturnValue方法, 
該方法內容就是爲response設置響應頭,然後將響應體的內容寫入response的body中,此時又會涉及到HttpMessageConverter,當HttpEntity中的body類型爲String,又會讓StringHttpMessageConverter來進行轉換。這和@ResponseBody的處理過程是一樣的。 

ViewNameMethodReturnValueHandler:主要用來處理返回值是String類型(前提不含@ResponseBody標籤),它會將返回的字符串作爲view視圖的名字,如下所示。 


另一種用法,當返回的字符串以redirect:開始,不再作爲view視圖名而是作爲重定向的地址,如下:
 
Java代碼  收藏代碼
  1. @RequestMapping(value="/test/string",method=RequestMethod.GET)  
  2.     public String testString(){  
  3.         return "redirect:/string";  
  4.     }  
  5.       

有了重定向,也有轉發。以forward:開頭便是轉發。 
如下: 
Java代碼  收藏代碼
  1. @RequestMapping(value="/test/string",method=RequestMethod.GET)  
  2.     public String testString(){  
  3.         return "forward:/string";  
  4.     }  

ModelMethodProcessor:用來處理返回類型爲Model的,它默認採用請求路徑作爲視圖名稱,如下: 
Java代碼  收藏代碼
  1. @RequestMapping(value="/test/model",method=RequestMethod.GET)  
  2.     public Model handleModel(String name) throws Exception {  
  3.         Model model=new ExtendedModelMap();  
  4.         model.addAttribute("name",name);  
  5.         return model;  
  6.     }  



ModelAndViewMethodReturnValueHandler:用來處理返回值類型爲ModelAndView,如下: 
Java代碼  收藏代碼
  1. @RequestMapping(value="/test/modelandview",method=RequestMethod.GET)  
  2.     public ModelAndView testModelAndView() throws Exception {  
  3.         return new ModelAndView("hello");  
  4.     }  


RequestResponseBodyMethodProcessor:則是用於處理方法中含有@ResponseBody註解,或類上含有@ResponseBody註解。這一處理過程在本系列的第三篇博客中有介紹,這裏不再敘述。 

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

轉載自:http://blog.csdn.net/z69183787/article/details/52817063

發佈了3 篇原創文章 · 獲贊 16 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章