在前面我们分析SpringMVC常见组件之HandlerAdapter分析中提到过如下过程:
RequestMappingHandlerAdapter.invokeAndHandle(webRequest, mavContainer); --ServletInvocableHandlerMethod.invokeAndHandle(webRequest, mavContainer); ---`Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);` ---this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
其中很重要的一步就是在HandlerMethodReturnValueHandlerComposite
中解析方法返回结果,方法源码如下所示:
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }
看到这里是不是就联想到了SpringMVC常见组件之HandlerMethodArgumentResolver解析中的HandlerMethodArgumentResolverComposite?没错,都是策略接口,应用了组合模式和中介者模式,将动作委派给具体的handler处理。
【1】HandlerMethodReturnValueHandler
方法返回结果处理器,其是一个策略接口,提供了两个方法让子类实现:supportsReturnType用来判断当前返回结果处理器是否能够处理返回结果,handleReturnValue方法用来处理返回结果。
public interface HandlerMethodReturnValueHandler { // 当前handler是否能够处理 MethodParameter returnType boolean supportsReturnType(MethodParameter returnType); //向model添加数据并设置view或者设置响应已经处理 void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; }
我们再来看一下其家族树图示
如下所示,有20个类,值得一提的是某些处理器还实现了参数解析器的接口,如
ModelMethodProcessor。 ViewNameMethodReturnValueHandler MapMethodProcessor ViewMethodReturnValueHandler StreamingResponseBodyReturnValueHandler DeferredResultMethodReturnValueHandler HandlerMethodReturnValueHandlerComposite HttpHeadersReturnValueHandler CallableMethodReturnValueHandler ModelMethodProcessor ModelAttributeMethodProcessor ServletModelAttributeMethodProcessor ResponseBodyEmitterReturnValueHandler ModelAndViewMethodReturnValueHandler ModelAndViewResolverMethodReturnValueHandler AbstractMessageConverterMethodProcessor RequestResponseBodyMethodProcessor HttpEntityMethodProcessor AsyncHandlerMethodReturnValueHandler AsyncTaskMethodReturnValueHandler
处理器与返回类型表格
如下表格中“是否解析参数”,也就是说其同时实现了HandlerMethodArgumentResolver接口,可以解析参数。
处理器 | 是否解析参数 | 类型 |
ModelAndViewMethodReturnValueHandler | 否 | ModelAndView |
ModelAndViewResolverMethodReturnValueHandler | 否 | 直接返回true |
ViewNameMethodReturnValueHandler | 否 | Void String CharSequence |
ViewMethodReturnValueHandler | 否 | View |
MapMethodProcessor | 是 |
Map |
ModelMethodProcessor | 是 |
Model |
ModelAttributeMethodProcessor | 是 |
标注了@ModelAttribute 的方法 |
RequestResponseBodyMethodProcessor | 是 |
标注了@ResponseBody 的方法 |
【2】HandlerMethodReturnValueHandlerComposite
通过将处理动作委派给内部注册的一系列HandlerMethodReturnValueHandler来实现功能。其内部有个常量集合如下:
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
其首先应用了组合模式,无论ServletInvocableHandlerMethod调用HandlerMethodReturnValueHandlerComposite还是单个具体的HandlerMethodReturnValueHandler,其行为都是一致的。
什么行为?第一是判断是否支持当前返回类型也就是supportsReturnType方法;第二就是处理返回结果的方法handleReturnValue。
其次应用了委派/策略模式,InvocableHandlerMethod在处理返回结果的时候根本不知道也不关心具体的HandlerMethodReturnValueHandler是谁,其根据supportsReturnType方法从returnValueHandlers中筛选一个合适的处理器进行结果处理。
① supportsReturnType
如下所示,HandlerMethodReturnValueHandlerComposite从returnValueHandlers中找到一个支持当前返回类型的handler,然后返回该HandlerMethodReturnValueHandler 。也就是将supportsReturnType的动作委派给了returnValueHandlers中的一个个具体的处理器。
@Override public boolean supportsReturnType(MethodParameter returnType) { return getReturnValueHandler(returnType) != null; } @Nullable private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) { for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (handler.supportsReturnType(returnType)) { return handler; } } return null; }
② handleReturnValue
如下所示,HandlerMethodReturnValueHandlerComposite首先从returnValueHandlers拿到一个合适的HandlerMethodReturnValueHandler 然后使用该处理器进行返回结果处理。如果没有找到合适的HandlerMethodReturnValueHandler ,将会抛出异常。
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } // 将动作转发给具体的handler handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } // 找到一个合适的HandlerMethodReturnValueHandler @Nullable private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } if (handler.supportsReturnType(returnType)) { return handler; } } return null; }
【3】ModelAndViewMethodReturnValueHandler
经典的视图处理器,处理返回结果类型为ModelAndView的值。该处理器将会把ModelAndView中的View信息和Model信息拷贝到ModelAndViewContainer中。如果返回结果为null,那么将会设置ModelAndViewContainer 的RequestHandled标志位true表名请求已经被直接处理完毕。
返回结果是ModelAndView类型的是有一种固定的用途,因此ModelAndViewMethodReturnValueHandler应该被配置在某些处理器前面(支持标注了@ModelAttribute或@ResponseBody注解的方法的返回结果类型的),以免被覆盖。
① supportsReturnType
异常简单,如下所示判断返回结果类型是否为ModelAndView。
@Override public boolean supportsReturnType(MethodParameter returnType) { return ModelAndView.class.isAssignableFrom(returnType.getParameterType()); }
② handleReturnValue
代码如下所示,首先判断返回值是否为空,如果为空则设置请求处理标志位为true表示当前请求已经被处理,返回返回。
接下来根据mav中的view是否是String进行不同的处理。这里需要注意的是进行了是否为重定向判断,如果是重定向如redirect:/user/list,那么将会设置RedirectModelScenario为true。最后设置status
并将mav
中的model
属性都放到了mavContainer
中。
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 判断是否为空 if (returnValue == null) { mavContainer.setRequestHandled(true); return; } ModelAndView mav = (ModelAndView) returnValue; // 判断当前mav中的view是否为String if (mav.isReference()) { String viewName = mav.getViewName(); mavContainer.setViewName(viewName); if (viewName != null && isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } else { View view = mav.getView(); mavContainer.setView(view); if (view instanceof SmartView && ((SmartView) view).isRedirectView()) { mavContainer.setRedirectModelScenario(true); } } //设置status mavContainer.setStatus(mav.getStatus()); // 放入model数据 mavContainer.addAllAttributes(mav.getModel()); }
【4】ModelMethodProcessor
其是一个参数解析器&&返回结果处理器,解析Model类型的参数并处理Model类型的返回结果。
同ModelAndViewMethodReturnValueHandler
一样,ModelMethodProcessor
应该被配置在某些处理器
前面(支持标注了@ModelAttribute
或@ResponseBody
注解的方法的返回结果类型的),以免被覆盖。
① supportsReturnType
判断方法如下所示,返回当前类型是否是Model。
@Override public boolean supportsReturnType(MethodParameter returnType) { return Model.class.isAssignableFrom(returnType.getParameterType()); }
② handleReturnValue
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { return; } else if (returnValue instanceof Model) { mavContainer.addAllAttributes(((Model) returnValue).asMap()); } else { // should not happen throw new UnsupportedOperationException("Unexpected return type [" + returnType.getParameterType().getName() + "] in method: " + returnType.getMethod()); } }
代码解释如下:
- ① 如果returnValue是null,则直接返回;
- ② 如果返回值是Model类型,则将model里面数据放入mavContainer;
- ③ 否则,抛出UnsupportedOperationException异常
【5】MapMethodProcessor
解析Map类型参数并能够处理Map类型的返回结果。
由于加了注解@ModelAttribute或者@ResponseBody方法也可能返回Map类型,因为在5.2版本后,这个解析器不处理标注了注解的方法参数。
① supportsReturnType
如下所示,判断返回类型是否为Map。
@Override public boolean supportsReturnType(MethodParameter returnType) { return Map.class.isAssignableFrom(returnType.getParameterType()); }
① supportsReturnType
如下所示,判断返回类型是否为Map。
@Override public boolean supportsReturnType(MethodParameter returnType) { return Map.class.isAssignableFrom(returnType.getParameterType()); }
② handleReturnValue
方法如下所示,如果返回类型是map,则将map放入mavContainer中。否则如果返回结果不为null,则抛出UnsupportedOperationException异常。
@Override @SuppressWarnings({"rawtypes", "unchecked"}) public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue instanceof Map){ mavContainer.addAllAttributes((Map) returnValue); } else if (returnValue != null) { // should not happen throw new UnsupportedOperationException("Unexpected return type [" + returnType.getParameterType().getName() + "] in method: " + returnType.getMethod()); } }
【6】ViewMethodReturnValueHandler
与视图相关,处理返回结果类型为View的。如果返回值为null,则由配置的RequestToViewNameTranslator按照约定选择视图名称。
同ModelAndViewMethodReturnValueHandler一样,ViewMethodReturnValueHandler应该被配置在某些处理器**前面(**支持标注了@ModelAttribute或@ResponseBody注解的方法的返回结果类型的),以免被覆盖。
① supportsReturnType
如下所示,ViewMethodReturnValueHandler只处理返回结果类型为View的。
@Override public boolean supportsReturnType(MethodParameter returnType) { return View.class.isAssignableFrom(returnType.getParameterType()); }
② handleReturnValue
在处理返回结果的时候,会判断返回结果是否为View类型,然后设置为mavContainer中的View引用。如果其是RedirectView则设置重定向模型场景标志为true,表示当前时重定向请求。如果其不是View类型并且结果不为null,则抛出UnsupportedOperationException异常。
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue instanceof View) { View view = (View) returnValue; mavContainer.setView(view); if (view instanceof SmartView && ((SmartView) view).isRedirectView()) { mavContainer.setRedirectModelScenario(true); } } else if (returnValue != null) { // should not happen throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); } }
【7】ViewNameMethodReturnValueHandler
与视图相关,处理返回结果为void、String以及基本的CharSequence。如果返回值为null,则由配置的RequestToViewNameTranslator按照约定选择视图名称。需要注意的是,ViewNameMethodReturnValueHandler应该被配置在某些处理器**后面(**支持标注了@ModelAttribute或@ResponseBody`注解的方法的返回结果类型的),以免覆盖。
① supportsReturnType
支持void类型或者CharSequence类型如String、StringBuilder。
@Override public boolean supportsReturnType(MethodParameter returnType) { Class<?> paramType = returnType.getParameterType(); return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType)); }
② handleReturnValue
如果返回结果不是CharSequence类型并且不为null,则直接抛出异常。如果返回结果是CharSequence类型,则设置mavContainer的viewName并尝试判断是否为重定向view而设置RedirectModelScenario为true。
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue instanceof CharSequence) { String viewName = returnValue.toString(); mavContainer.setViewName(viewName); if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } else if (returnValue != null) { // should not happen throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); } }
SpringMVC常见组件之HandlerMethodReturnValueHandler解析-2+https://developer.aliyun.com/article/1382028