SpringMVC源码总结(六)mvc:annotation-driven中的HandlerMethodReturnValueHandler

来源:互联网 发布:sql to_date 编辑:程序博客网 时间:2024/05/16 09:41
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有个整体的认识,具体的内容,需要读者去具体研究。
0 0
原创粉丝点击