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 ...
随机推荐
- HandlerMethodArgumentResolver 自定义使用
HandlerMethodArgumentResolver 自定义使用 1.HandlerMethodArgumentResolver 的应用场景 HandlerMethodArgumentRes ...
- FinOps for Kubernetes - 如何拆分 Kubernetes 成本
本文独立博客阅读地址:https://thiscute.world/posts/finops-for-kubernetes/ 目录 云计算成本管控 Kubernetes 成本分析的难点 Kuberne ...
- 用上这个 Mock 神器,让你的开发爽上天!
前端的痛苦 作为前端,最痛苦的是什么时候? 每个迭代,需求文档跟设计稿都出来了,静态页面唰唰两天就做完了.可是做前端又不是简单地把后端吐出来的数据放到页 面上就完了,还有各种前端处理逻辑啊. 后端 ...
- animation—延迟和持续时间
animation: moveToRight .75s 6s linear infinite ;animation: moveToRight -.75s 1.5s linear infinite; ...
- sklearn机器学习-特征提取1
scikit-learn机器学习的特征提取部分较多nlp内容,故学到一半学不下去,看完nltk再来补上 scikit-learn机器学习的特征提取这一章感觉讲的不是特别好,所以会结合着来看 首先是Di ...
- 使用echo 无法正确清空文件存储大小
在使用echo进行重定向文件的时候,会存在大小没有发生改变的现象 使用上面的方法遇到一个现象 ls -l 与 du -sh 得到的大小事是不同的 可以尝试下面的方面之后在进行对比 再看是否正确清除 使 ...
- js循环调用axios异步请求,实现同步
准备: const axios = require('axios'); // axios请求 const res = []; const arr = ["a", "b&q ...
- 树莓派使用Docker部署EdgeX(jakarta版本)
使用Docker部署EdgeX 老师安排我搞边缘计算,搞了很久都没能明白边缘计算是什么,甚至对其兴趣不大,前一阵弄好了lorawan网关,该做网关内部的边缘计算了,发现自己已经慢慢地学了进去,总是想要 ...
- 拥抱Spring全新OAuth解决方案
以下全文 Spring Authorization Server 简称为: SAS 背景 Spring 团队正式宣布 Spring Security OAuth 停止维护,该项目将不会再进行任何的迭代 ...
- @vue/cli3+配置build命令构建测试包&正式包
上一篇博客介绍了vue-cli2.x配置build命令构建测试包和正式包,但现在前端开发vue项目大多数使用新版@vue/cli脚手架搭建vue项目(vue create project-name) ...