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

简介:
经过了两篇的乱码说明,要重新回到mvc:annotation-driven标签中,继续说说HandlerMethodReturnValueHandler的使用,下一篇文章主要说说HttpMessageConverter。 

HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用来处理当含有@RequestMapping的方法调度完成后,后面要进行的事情。 
首先是HandlerMethodReturnValueHandler的自定义注册: 
mvc:annotation-driven配置如下:
 
?
1
2
3
4
5
<mvc:annotation-driven>
         <mvc: return -value-handlers>
             <bean class = "org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler" ></bean>
         </mvc: return -value-handlers>
     </mvc:annotation-driven>

在启动AnnotationDrivenBeanDefinitionParser来解析mvc:annotation-driven标签的过程中(见本系列第三篇博客),会注册我们所配置的HandlerMethodReturnValueHandler,如下:  
?
1
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);

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

然后将会这些自定义的HandlerMethodReturnValueHandler设置到RequestMappingHandlerAdapter的customReturnValueHandlers属性中, 

RequestMappingHandlerAdapter的两个重要属性: 
customReturnValueHandlers:存放我们自定义的HandlerMethodReturnValueHandler; 
returnValueHandlers:存放最终所有的HandlerMethodReturnValueHandler; 
如下所示:
 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
         implements BeanFactoryAware, InitializingBean {
 
     private List<HandlerMethodArgumentResolver> customArgumentResolvers;
 
     private HandlerMethodArgumentResolverComposite argumentResolvers;
 
     private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
 
//这里这里这里这里这里这里这里这里
     private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
//这里这里这里这里这里这里这里这里
     private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

returnValueHandlers的属性类型为HandlerMethodReturnValueHandlerComposite,里面也有一个list集合,来存放所有的HandlerMethodReturnValueHandler。 
HandlerMethodReturnValueHandlerComposite结构如下:
 
?
1
2
3
4
5
6
7
8
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
 
     protected final Log logger = LogFactory.getLog(getClass());
 
     private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
         new ArrayList<HandlerMethodReturnValueHandler>();
 
     /**

在RequestMappingHandlerAdapter创建出来后,会执行afterPropertiesSet()方法,在该方法中会设置所有的HandlerMethodReturnValueHandler到RequestMappingHandlerAdapter的returnValueHandlers属性中如下:  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
     public void afterPropertiesSet() {
         if ( this .argumentResolvers == null ) {
             List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
             this .argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
         }
         if ( this .initBinderArgumentResolvers == null ) {
             List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
             this .initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
         }
         if ( this .returnValueHandlers == null ) {
//获取所有的HandlerMethodReturnValueHandler
             List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
             this .returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
         }
         initControllerAdviceCache();
     }

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

至此,所有的HandlerMethodReturnValueHandler的注册已经完成。我们可以再回顾下,在该系列的第三篇博客中介绍HandlerMethodReturnValueHandler的使用。 
第一步:获取合适的HandlerAdapter,当方法含有@RequestMaiing注释的时候,便选择RequestMappingHandlerAdapter来进行方法的调度处理 
第二步:方法的调度处理过程为:首先执行方法体,然后根据返回值来选择一个合适的HandlerMethodReturnValueHandler,如下代码:
 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public final void invokeAndHandle(ServletWebRequest webRequest,
             ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
 
         Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
 
         setResponseStatus(webRequest);
 
         if (returnValue == null ) {
             if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
                 mavContainer.setRequestHandled( true );
                 return ;
             }
         }
         else if (StringUtils.hasText( this .responseReason)) {
             mavContainer.setRequestHandled( true );
             return ;
         }
 
         mavContainer.setRequestHandled( false );
//重点重点重点重点重点重点重点重点重点重点
         try {
             this .returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
         }
         catch (Exception ex) {
             if (logger.isTraceEnabled()) {
                 logger.trace(getReturnValueHandlingErrorMessage( "Error handling return value" , returnValue), ex);
             }
             throw ex;
         }
     }

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

找到支持的HandlerMethodReturnValueHandler后,就要执行它的handleReturnValue方法。 
下面就具体介绍下下常用的这几个HandlerMethodReturnValueHandler; 
HttpEntityMethodProcessor:用来处理返回值类型是HttpEntity的方法,简单用法如下
 
?
1
2
3
4
5
6
7
8
@RequestMapping (value= "/test/httpEntity" ,method=RequestMethod.GET)
     public HttpEntity<String> testHttpEntity() throws UnsupportedEncodingException{
         String body= "中国" ;
         HttpHeaders headers= new HttpHeaders();
         headers.add( "Content-type" , "text/html;charset=GBK" );
         HttpEntity<String> ret= new HttpEntity<String>(body,headers);
         return ret;
     }

就是在构建http协议的返回体和返回头。 

使用案例如,文件下载。 
经常有人直接用HttpServletRequest和HttpServletResponse来做文件下载,这种方式便与web容器产生的对象耦合在一起,不推荐使用,而是直接使用spring为我们提供的HttpEntityMethodProcessor这一返回值处理器,虽然springmvc最终还是用HttpServletResponse来实现,但是这种方式便断开我们直接与web容器之间的耦合。 

这一过程分析: 
当这个方法执行完成之后,会调用HttpEntityMethodProcessor的handleReturnValue方法, 
该方法内容就是为response设置响应头,然后将响应体的内容写入response的body中,此时又会涉及到HttpMessageConverter,当HttpEntity中的body类型为String,又会让StringHttpMessageConverter来进行转换。这和@ResponseBody的处理过程是一样的。 

ViewNameMethodReturnValueHandler:主要用来处理返回值是String类型(前提不含@ResponseBody标签),它会将返回的字符串作为view视图的名字,如下所示。 

07110843_EeW4.png 
另一种用法,当返回的字符串以redirect:开始,不再作为view视图名而是作为重定向的地址,如下:
 
?
1
2
3
4
@RequestMapping (value= "/test/string" ,method=RequestMethod.GET)
     public String testString(){
         return "redirect:/string" ;
     }

有了重定向,也有转发。以forward:开头便是转发。  
如下: 
?
1
2
3
4
@RequestMapping (value= "/test/string" ,method=RequestMethod.GET)
     public String testString(){
         return "forward:/string" ;
     }

ModelMethodProcessor:用来处理返回类型为Model的,它默认采用请求路径作为视图名称,如下:  
?
1
2
3
4
5
6
@RequestMapping (value= "/test/model" ,method=RequestMethod.GET)
     public Model handleModel(String name) throws Exception {
         Model model= new ExtendedModelMap();
         model.addAttribute( "name" ,name);
         return model;
     }


07110844_n5Kk.png  
ModelAndViewMethodReturnValueHandler:用来处理返回值类型为ModelAndView,如下:  
?
1
2
3
4
@RequestMapping (value= "/test/modelandview" ,method=RequestMethod.GET)
     public ModelAndView testModelAndView() throws Exception {
         return new ModelAndView( "hello" );
     }


RequestResponseBodyMethodProcessor:则是用于处理方法中含有@ResponseBody注解,或类上含有@ResponseBody注解。这一处理过程在本系列的第三篇博客中有介绍,这里不再叙述。 
还有其他的HandlerMethodReturnValueHandler,这里仅仅是作为引路,对HandlerMethodReturnValueHandler有个整体的认识,具体的内容,需要读者去具体研究。
相关文章
|
4月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】
|
4月前
|
前端开发 安全 Java
SpringMVC基础篇:第一个MVC程序和细节分析
SpringMVC基础篇:第一个MVC程序和细节分析
|
4月前
|
前端开发 Java 应用服务中间件
SpringMVC基础篇:MVC基础知识
vSpringMVC基础篇:MVC基础知识
|
23天前
|
前端开发 JavaScript Java
MVC框架:SpringMVC(三)
MVC框架:SpringMVC
30 0
|
23天前
|
JSON 前端开发 JavaScript
MVC框架:SpringMVC(二)
MVC框架:SpringMVC
35 0
|
23天前
|
前端开发 Java 应用服务中间件
MVC框架:SpringMVC(一)
MVC框架:SpringMVC
58 0
|
3月前
|
前端开发 Java Spring
【Spring MVC】SpringMVC自动配置
【1月更文挑战第14天】【Spring MVC】SpringMVC自动配置
|
4月前
|
设计模式 前端开发 Java
Spring Boot之Spring MVC的工作原理 以及使用eclipse开发Spring MVC的Web应用实战(附源码)
Spring Boot之Spring MVC的工作原理 以及使用eclipse开发Spring MVC的Web应用实战(附源码)
45 0
|
4月前
|
XML 前端开发 Java
SpringMVC中<mvc:annotation-driven/>标签原理与实践详解
SpringMVC中<mvc:annotation-driven/>标签原理与实践详解
43 0
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
38 0