HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用來處理當含有@RequestMapping的方法調度完成後,後面要進行的事情。
首先是HandlerMethodReturnValueHandler的自定義註冊:
mvc:annotation-driven配置如下:
- <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,如下:
- 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<HandlerMethodArgumentResolver> customArgumentResolvers;
- private HandlerMethodArgumentResolverComposite argumentResolvers;
- private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
- //這裏這裏這裏這裏這裏這裏這裏這裏
- private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
- //這裏這裏這裏這裏這裏這裏這裏這裏
- private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
returnValueHandlers的屬性類型爲HandlerMethodReturnValueHandlerComposite,裏面也有一個list集合,來存放所有的HandlerMethodReturnValueHandler。
HandlerMethodReturnValueHandlerComposite結構如下:
- 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屬性中如下:
- @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,如下:
- 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,如下代碼:
- 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<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視圖的名字,如下所示。
另一種用法,當返回的字符串以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;
- }
ModelAndViewMethodReturnValueHandler:用來處理返回值類型爲ModelAndView,如下:
- @RequestMapping(value="/test/modelandview",method=RequestMethod.GET)
- public ModelAndView testModelAndView() throws Exception {
- return new ModelAndView("hello");
- }
RequestResponseBodyMethodProcessor:則是用於處理方法中含有@ResponseBody註解,或類上含有@ResponseBody註解。這一處理過程在本系列的第三篇博客中有介紹,這裏不再敘述。
還有其他的HandlerMethodReturnValueHandler,這裏僅僅是作爲引路,對HandlerMethodReturnValueHandler有個整體的認識,具體的內容,需要讀者去具體研究。
轉載自:http://blog.csdn.net/z69183787/article/details/52817063