springmvc源码笔记-HandlerMethodReturnValueHandler
返回值解析器
用于对controller的返回值进行二次处理
结构
// 返回值解析器
public interface HandlerMethodReturnValueHandler {
// 判断 HandlerMethodReturnValueHandler 是否支持 MethodParameter
boolean supportsReturnType(MethodParameter returnType);
// 处理给定的返回值
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
调用
完整调用链
DispatcherServlet#doDispatch()
AbstractHandlerMethodAdapter#handle()
RequestMappingHandlerAdapter#handleInternal()
// 在这里会创建ServletInvocableHandlerMethod,此时已经将controller的函数(HandlerMethod)的参数注入到InvocableHandlerMethod(类变量)中
RequestMappingHandlerAdapter#invokeHandlerMethod()
// 在这里,invokeForRequest通过反射的方式调用controller中的方法并返回returnValue
ServletInvocableHandlerMethod#invokeAndHandle()
// 处理返回值方法
HandlerMethodReturnValueHandlerComposite#handleReturnValue
// 获取返回值处理器
HandlerMethodReturnValueHandlerComposite#selectHandler
// 处理返回值
HandlerMethodReturnValueHandler#handleReturnValue
RequestMappingHandlerAdapter#invokeHandlerMethod()中调用了controller,并得到了返回值
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 调用handler(controller+method),得到返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
。。。。。。
try {
// 处理返回值方法
// returnValueHandlers是HandlerMethodReturnValueHandlerComposite类
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
接下来,就轮到HandlerMethodReturnValueHandlerComposite表演了
// 处理返回值
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就是HandlerMethodReturnValueHandler的实现类
// HandlerMethodReturnValueHandler#handleReturnValue处理返回值
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
// 查找处理器
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// returnValueHandlers就是HandlerMethodReturnValueHandler的实现类集合,默认有15个实现类
// 注意:returnValueHandlers是有顺序的
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
// 使用supportsReturnType方法判断该处理器是否支持解析当前返回值
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
执行顺序
HandlerMethodReturnValueHandler的调用是有执行顺序的,如果自定义的HandlerMethodReturnValueHandler没有被触发,请检查是否被其他handler抢先了
| 处理器 | 处理类型 | 处理种类 |
|---|---|---|
| ModelAndViewMethodReturnValueHandler | ModelAndView | 一种类型 |
| ModelMethodProcessor | Model | 一种类型 |
| ViewMethodReturnValueHandler | View | 一种类型 |
| ResponseBodyEmitterReturnValueHandler | ResponseEntity | 一种类型 |
| StreamingResponseBodyReturnValueHandler | ResponseEntity | 一种类型 |
| HttpHeadersReturnValueHandler | HttpHeaders | 一种类型 |
| CallableMethodReturnValueHandler | Callable | 一种类型 |
| DeferredResultMethodReturnValueHandler | DeferredResult、ListenableFuture、CompletionStage | 一种类型 |
| AsyncTaskMethodReturnValueHandler | WebAsyncTask | 一种类型 |
| ModelAttributeMethodProcessor | @ModelAttribute(require=false) | 针对注解 |
| RequestResponseBodyMethodProcessor | @ResponseBody | 针对注解 |
| ViewNameMethodReturnValueHandler | void、CharSequence(V4.2) | 多种类型 |
| MapMethodProcessor | Map | 多种类型 |
| 自定义返回值处理器 | 自定义 | |
| ServletModelAttributeMethodProcessor | 兜底方法 |
springmvc源码笔记-HandlerMethodReturnValueHandler的更多相关文章
- springmvc源码笔记-RequestMappingHandlerMapping
下图是springmvc的执行流程 图片来源:https://www.jianshu.com/p/8a20c547e245 DispatcherServlet根据url定位到Controller和方法 ...
- springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)
HandlerMethodReturnValueHandler是用于对Controller中函数执行的返回值进行处理操作的,springMVC提供了多个HandlerMethodReturnValue ...
- springMVC源码笔记
springMVC 设计总览 下图来源:https://www.cnblogs.com/fangjian0423/p/springMVC-directory-summary.html 下图来源:htt ...
- springmvc源码笔记-HandlerMapping注入
在springmvc中,如何根据url找到controller以及对应方法,依赖的是HandlerMapping接口的getHandler方法 在spring容器中默认注册的HandlerMappin ...
- springMVC源码分析--ViewNameMethodReturnValueHandler返回值处理器(三)
之前两篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)和springMVC源码分析--HandlerMethodReturnValu ...
- springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)
在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...
- springMVC源码分析--HttpMessageConverter写write操作(三)
上一篇博客springMVC源码分析--HttpMessageConverter参数read操作中我们已经简单介绍了参数值转换的read操作,接下来我们介绍一下返回值的处理操作.同样返回值的操作操作也 ...
- springMVC源码分析--HttpMessageConverter数据转化(一)
之前的博客我们已经介绍了很多springMVC相关的模块,接下来我们介绍一下springMVC在获取参数和返回结果值方面的处理.虽然在之前的博客老田已经分别介绍了参数处理器和返回值处理器: (1)sp ...
- SpringMVC源码分析系列
说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...
随机推荐
- Docker系列教程04-Docker构建镜像的三种方式
简介 创建镜像的方法主要有三种:基于已有镜像的容器创建.基于本地模板导入.基于Dockerfile创建. 今天就逐一讲述为大家讲述,如何构建属于自己的docker镜像. 1.基于容器构建镜像 基于已有 ...
- data structure assignment problem record
Question1: Similar to pause command in linux read -n 1 Question2 read : Illegal option -n 原因为ubuntu ...
- idea的快捷键(复制) IntelliJ Idea 常用快捷键列表
Ctrl+Shift + Enter,语句完成'!',否定完成,输入表达式时按 "!"键 Ctrl+E,最近的文件Ctrl+Shift+E,最近更改的文件Shift+Click,可 ...
- Java中的线程到底有哪些安全策略
摘要:Java中的线程到底有哪些安全策略呢?本文就为你彻底分析下! 本文分享自华为云社区<[高并发]线程安全策略>,作者:冰 河 . 一.不可变对象 不可变对象需要满足的条件 (1)对象创 ...
- 透过实例demo带你认识gRPC
摘要:gRPC是基于定义一个服务,指定一个可以远程调用的带有参数和返回类型的的方法.在服务端,服务实现这个接口并且运行gRPC服务处理客户端调用. 本文分享自华为云社区<gRPC介绍以及spri ...
- final变量、方法与类
学习内容: 一.final变量 1.设定为final的变量,其值不可被改变. 2.final定义的变量必须在声明时对其进行赋值操作. 3.final可以修饰对象.被修饰为final的对象,只能恒定指向 ...
- 羿网通WT2100网络测试仪端口开关功能应用案例
端口开关是羿网通WT2100具备的一项全局性的功能,使用客户端软件Packlark连接WT2100后无需进入具体功能即可使用.该功能是通过控制设备上的以太网开关实现快速.便捷地切换网口通断状态的目标, ...
- HCNP Routing&Switching之VRRP基础
前文我们了解了链路高可用技术链路聚合相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16279078.html:今天我们来聊一聊另一种高可用技术,网关高 ...
- Datax源码改造关键步骤记录
Datax源码改造关键步骤记录: 一.作业配置1.一个job配置:reader 和writer 的column 字段必须是所有表共有的:2.reader多张表,writer一个表时,所有reader的 ...
- BitBlt()函数实现带数字百分比进度条控件、静态文本(STATIC)控件实现的位图进度条、自定义进度条控件实现七彩虹颜色带数字百分比
Windows API BitBlt()函数实现带数字百分比进度条控件. 有两个例子:一用定时器实现,二用多线程实现. 带有详细注解. 此例是本人原创,绝对是网上稀缺资源(本源码用Windows AP ...