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

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

HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用来处理当含有@RequestMapping的方法调度完成后,后面要进行的事情。
首先是HandlerMethodReturnValueHandler的自定义注册:
mvc:annotation-driven配置如下:[/size]

<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>

[size=medium]在启动AnnotationDrivenBeanDefinitionParser来解析mvc:annotation-driven标签的过程中(见本系列第三篇博客),会注册我们所配置的HandlerMethodReturnValueHandler,如下:[/size]

ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);


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

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

RequestMappingHandlerAdapter的两个重要属性:
customReturnValueHandlers:存放我们自定义的HandlerMethodReturnValueHandler;
returnValueHandlers:存放最终所有的HandlerMethodReturnValueHandler;
如下所示:[/size]

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;


[size=medium]returnValueHandlers的属性类型为HandlerMethodReturnValueHandlerComposite,里面也有一个list集合,来存放所有的HandlerMethodReturnValueHandler。
HandlerMethodReturnValueHandlerComposite结构如下:[/size]

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {

protected final Log logger = LogFactory.getLog(getClass());

private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
new ArrayList<HandlerMethodReturnValueHandler>();

/**

[size=medium]在RequestMappingHandlerAdapter创建出来后,会执行afterPropertiesSet()方法,在该方法中会设置所有的HandlerMethodReturnValueHandler到RequestMappingHandlerAdapter的returnValueHandlers属性中如下:[/size]

@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();
}

[size=medium]getDefaultReturnValueHandlers()方法会获取默认要注册的和我们自定义的HandlerMethodReturnValueHandler,如下:[/size]

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;
}


[size=medium]至此,所有的HandlerMethodReturnValueHandler的注册已经完成。我们可以再回顾下,在该系列的第三篇博客中介绍HandlerMethodReturnValueHandler的使用。
第一步:获取合适的HandlerAdapter,当方法含有@RequestMaiing注释的时候,便选择RequestMappingHandlerAdapter来进行方法的调度处理
第二步:方法的调度处理过程为:首先执行方法体,然后根据返回值来选择一个合适的HandlerMethodReturnValueHandler,如下代码:[/size]

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;
}
}

[size=medium]this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest)会遍历所有的已注册的HandlerMethodReturnValueHandler判断他们支不支持returnValue的返回类型。如下:[/size]

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;
}

[size=medium]找到支持的HandlerMethodReturnValueHandler后,就要执行它的handleReturnValue方法。
下面就具体介绍下下常用的这几个HandlerMethodReturnValueHandler;
HttpEntityMethodProcessor:用来处理返回值类型是HttpEntity的方法,简单用法如下[/size]

@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;
}

[size=medium]就是在构建http协议的返回体和返回头。

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

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

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

[img]http://dl2.iteye.com/upload/attachment/0100/5530/bb975463-d2d7-3da4-8be2-6f1651830328.png[/img]
另一种用法,当返回的字符串以redirect:开始,不再作为view视图名而是作为重定向的地址,如下:[/size]

@RequestMapping(value="/test/string",method=RequestMethod.GET)
public String testString(){
return "redirect:/string";
}


[size=medium]有了重定向,也有转发。以forward:开头便是转发。[/size]
如下:

@RequestMapping(value="/test/string",method=RequestMethod.GET)
public String testString(){
return "forward:/string";
}

[size=medium]ModelMethodProcessor:用来处理返回类型为Model的,它默认采用请求路径作为视图名称,如下:[/size]

@RequestMapping(value="/test/model",method=RequestMethod.GET)
public Model handleModel(String name) throws Exception {
Model model=new ExtendedModelMap();
model.addAttribute("name",name);
return model;
}


[img]http://dl2.iteye.com/upload/attachment/0100/5532/dab8e003-4fae-3c4b-8191-fe3a6204aa31.png[/img]
[size=medium]ModelAndViewMethodReturnValueHandler:用来处理返回值类型为ModelAndView,如下:[/size]

@RequestMapping(value="/test/modelandview",method=RequestMethod.GET)
public ModelAndView testModelAndView() throws Exception {
return new ModelAndView("hello");
}

[size=medium]
RequestResponseBodyMethodProcessor:则是用于处理方法中含有@ResponseBody注解,或类上含有@ResponseBody注解。这一处理过程在本系列的第三篇博客中有介绍,这里不再叙述。
还有其他的HandlerMethodReturnValueHandler,这里仅仅是作为引路,对HandlerMethodReturnValueHandler有个整体的认识,具体的内容,需要读者去具体研究。[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值