博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC源码总结(六)mvc:annotation-driven中的HandlerMethodReturnValueHandler
阅读量:6929 次
发布时间:2019-06-27

本文共 9051 字,大约阅读时间需要 30 分钟。

hot3.png

经过了两篇的乱码说明,要重新回到mvc:annotation-driven标签中,继续说说HandlerMethodReturnValueHandler的使用,下一篇文章主要说说HttpMessageConverter。
HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用来处理当含有@RequestMapping的方法调度完成后,后面要进行的事情。
首先是HandlerMethodReturnValueHandler的自定义注册:
mvc:annotation-driven配置如下:
在启动AnnotationDrivenBeanDefinitionParser来解析mvc:annotation-driven标签的过程中(见本系列第三篇博客),会注册我们所配置的HandlerMethodReturnValueHandler,如下:
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; }
然后将会这些自定义的HandlerMethodReturnValueHandler设置到RequestMappingHandlerAdapter的customReturnValueHandlers属性中,
RequestMappingHandlerAdapter的两个重要属性:
customReturnValueHandlers:存放我们自定义的HandlerMethodReturnValueHandler;
returnValueHandlers:存放最终所有的HandlerMethodReturnValueHandler;
如下所示:
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter		implements BeanFactoryAware, InitializingBean {	private List
customArgumentResolvers; private HandlerMethodArgumentResolverComposite argumentResolvers; private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;//这里这里这里这里这里这里这里这里 private List
customReturnValueHandlers;//这里这里这里这里这里这里这里这里 private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
returnValueHandlers的属性类型为HandlerMethodReturnValueHandlerComposite,里面也有一个list集合,来存放所有的HandlerMethodReturnValueHandler。
HandlerMethodReturnValueHandlerComposite结构如下:
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {	protected final Log logger = LogFactory.getLog(getClass());	private final List
returnValueHandlers = new ArrayList
(); /**
在RequestMappingHandlerAdapter创建出来后,会执行afterPropertiesSet()方法,在该方法中会设置所有的HandlerMethodReturnValueHandler到RequestMappingHandlerAdapter的returnValueHandlers属性中如下:
@Override	public void afterPropertiesSet() {		if (this.argumentResolvers == null) {			List
resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.initBinderArgumentResolvers == null) { List
resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.returnValueHandlers == null) {//获取所有的HandlerMethodReturnValueHandler List
handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } initControllerAdviceCache(); }
getDefaultReturnValueHandlers()方法会获取默认要注册的和我们自定义的HandlerMethodReturnValueHandler,如下:
private List
getDefaultReturnValueHandlers() { List
handlers = new ArrayList
(); // 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,如下代码:
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的返回类型。如下:
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的方法,简单用法如下
@RequestMapping(value="/test/httpEntity",method=RequestMethod.GET)	public HttpEntity
testHttpEntity() throws UnsupportedEncodingException{ String body="中国"; HttpHeaders headers=new HttpHeaders(); headers.add("Content-type","text/html;charset=GBK"); HttpEntity
ret=new HttpEntity
(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视图的名字,如下所示。
30150414_1kIi.png
另一种用法,当返回的字符串以redirect:开始,不再作为view视图名而是作为重定向的地址,如下:
@RequestMapping(value="/test/string",method=RequestMethod.GET)	public String testString(){		return "redirect:/string";	}
有了重定向,也有转发。以forward:开头便是转发。
如下:
@RequestMapping(value="/test/string",method=RequestMethod.GET)	public String testString(){		return "forward:/string";	}
ModelMethodProcessor:用来处理返回类型为Model的,它默认采用请求路径作为视图名称,如下:
@RequestMapping(value="/test/model",method=RequestMethod.GET)	public Model handleModel(String name) throws Exception {		Model model=new ExtendedModelMap();		model.addAttribute("name",name);		return model;	}
30150414_C7Jp.png
ModelAndViewMethodReturnValueHandler:用来处理返回值类型为ModelAndView,如下:
@RequestMapping(value="/test/modelandview",method=RequestMethod.GET)	public ModelAndView testModelAndView() throws Exception {		return new ModelAndView("hello");	}
RequestResponseBodyMethodProcessor:则是用于处理方法中含有@ResponseBody注解,或类上含有@ResponseBody注解。这一处理过程在本系列的第三篇博客中有介绍,这里不再叙述。
还有其他的HandlerMethodReturnValueHandler,这里仅仅是作为引路,对HandlerMethodReturnValueHandler有个整体的认识,具体的内容,需要读者去具体研究。

转载于:https://my.oschina.net/Sheamus/blog/393596

你可能感兴趣的文章
培训课程大纲
查看>>
Atitit. Ati IDE 开发平台的第一版规划
查看>>
总结oninput、onchange与onpropertychange事件的用法和区别
查看>>
【Android】12.6 利用Intent实现记事本功能(NotePad)
查看>>
php将文件转换成二进制输出[转]
查看>>
微信JS SDK Demo
查看>>
base64编码、解码的C语言实现
查看>>
HTML5中Access-Control-Allow-Origin解决跨域问题
查看>>
android: 服务的生命周期
查看>>
JBoss7安装、测试、配置和启动以及停止,部署
查看>>
[备忘]Redis运行出现Client sent AUTH, but no password is set
查看>>
PHP判断远程文件是否存在
查看>>
函数传递一维数组
查看>>
WebComponent魔法堂:深究Custom Element 之 从过去看现在
查看>>
Picard 法求方程根
查看>>
c语言中有bool型变量吗?
查看>>
Null值的使用
查看>>
《程序设计与数据结构》 课程教学
查看>>
注册asp.net
查看>>
java.net.ProtocolException: Exceeded stated content-length of: '13824' bytes
查看>>