当前位置:网站首页>八、响应处理——ReturnValueHandler匹配返回值处理器并处理返回值原理解析
八、响应处理——ReturnValueHandler匹配返回值处理器并处理返回值原理解析
2022-08-05 05:16:00 【呆比特】
响应处理——ReturnValueHandler匹配返回值处理器并处理返回值原理解析
前边已经分析了请求处理中从映射到获取参数值等底层原理,接下来的几篇将学习一下响应处理的相关过程
这一片学习Spring MVC如何快速返回一个JSON数据
首先我们的项目已经引入了 web 场景,web 场景中已经自动引入了 json 相关依赖
现在先写一个简单的controller来测试一下
//利用返回值处理器里面的消息转换器进行处理
@ResponseBody
@GetMapping(value = "/test/person")
public Person getPerson(){
Person person = new Person();
person.setAge(28);
person.setBirth(new Date());
person.setUserName("zhangsan");
return person;
}

接下来老套路,debug探索一下它的原理
直接跳过前边请求处理部分,来到真正处理请求的 RequestMappingHandlerAdapter.class 的 invokeHandlerMethod() 方法

在前边处理请求参数的时候,有一个参数解析器,同样,在处理返回值时,也有一个 返回值处理器
在方法返回之前,我们的返回值处理器已经准备好了,只等我们返回值时拿这些处理器来处理
下一步代码到 ServletInvocableHandlerMethod.class 的 invokeAndHandle 方法
以前我们是进到 invokeForRequest 方法看它怎么处理请求,现在就直接跳过往下走了

handleReturnValue 方法传入了我们的返回值对象,还有返回值类型,接下来,就在这个方法里边,利用对应的返回值处理器,帮我们处理返回值

我们前边的controller标注了 @ResponseBody , RequestResponseBodyMethodProcessor 处理器可以处理 @ResponseBody ,所以拿到了它

找到了处理器,接下来就看它是怎样处理的
step into 进入 RequestResponseBodyMethodProcessor.class 的 handleReturnValue 方法
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
//包装原生request、response
ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
//传入返回值,返回值类型,以及请求响应,使用消息转换器进行写出操作
this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
进入 writeWithMessageConverters 方法,下边要进行的操作叫做 内容协商 ,浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型,服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据
//省略前边一些判断代码,直接来到内容协商
MediaType selectedMediaType = null;
//先看响应头中有没有内容类型
MediaType contentType = outputMessage.getHeaders().getContentType();
boolean isContentTypePreset = contentType != null && contentType.isConcrete();
if (isContentTypePreset) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Found 'Content-Type:" + contentType + "' in response");
}
//如果已经有了,就直接用
selectedMediaType = contentType;
} else {
//如果没有,就拿到原生 request 对象,
HttpServletRequest request = inputMessage.getServletRequest();
//获取能接受的内容类型,就是响应头中Accept的内容
List<MediaType> acceptableTypes = this.getAcceptableMediaTypes(request);
//最终能生成的内容类型
List<MediaType> producibleTypes = this.getProducibleMediaTypes(request, valueType, (Type)targetType);
if (body != null && producibleTypes.isEmpty()) {
throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);
}
List<MediaType> mediaTypesToUse = new ArrayList();
Iterator var15 = acceptableTypes.iterator();
//服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据
MediaType mediaType;
while(var15.hasNext()) {
mediaType = (MediaType)var15.next();
Iterator var17 = producibleTypes.iterator();
while(var17.hasNext()) {
MediaType producibleType = (MediaType)var17.next();
if (mediaType.isCompatibleWith(producibleType)) {
mediaTypesToUse.add(this.getMostSpecificMediaType(mediaType, producibleType));
}
}
}
if (mediaTypesToUse.isEmpty()) {
if (body != null) {
throw new HttpMediaTypeNotAcceptableException(producibleTypes);
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);
}
return;
}
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
var15 = mediaTypesToUse.iterator();
while(var15.hasNext()) {
mediaType = (MediaType)var15.next();
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
经过上边的代码,就拿到了内容类型
拿到了内容类型之后,SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?

循环判断默认的MessageConverter看哪个能干活
找到了 MappingJackson2HttpMessageConverter ,它的supports方法直接返回true,啥都支持

最终,利用MappingJackson2HttpMessageConverter将对象转为json再写出去

总结
1. 返回值处理器判断是否支持这种类型返回值 supportsReturnType
2. 返回值处理器调用 handleReturnValue 进行处理
3. RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。
利用 MessageConverters 进行处理 将数据写为json
①内容协商(浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型)
②服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据,
③SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?
得到MappingJackson2HttpMessageConverter可以将对象写为json
利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
OVER(∩_∩)O~
边栏推荐
- flink部署操作-flink on yarn集群安装部署
- SQL (2) - join window function view
- Comparison and summary of Tensorflow2 and Pytorch in terms of basic operations of tensor Tensor
- 【数据库和SQL学习笔记】4.SELECT查询2:排序(ORDER BY)、聚合函数、分组查询(GROUP BY)
- 《基于机器视觉测量系统的工业在线检测研究》论文笔记
- The University of Göttingen proposed CLIPSeg, a model that can perform three segmentation tasks at the same time
- 网工必用神器:网络排查工具MTR
- 单片机按键开发库-支持连击、长按等操作
- 大型Web网站高并发架构方案
- Kubernetes常备技能
猜你喜欢

The difference between the operators and logical operators

AIDL详解

CVPR2021 - Inception Convolution with Efficient Dilation Search

MSRA proposes extreme masking model ExtreMA for learning instances and distributed visual representations

面向小白的深度学习代码库,一行代码实现30+中attention机制。

It turns out that the MAE proposed by He Yuming is still a kind of data enhancement

【数据库和SQL学习笔记】3.数据操纵语言(DML)、SELECT查询初阶用法

MaskDistill - Semantic segmentation without labeled data
![[Pytorch study notes] 10. How to quickly create your own Dataset dataset object (inherit the Dataset class and override the corresponding method)](/img/71/f82e76085f9d8e6610f6f817e2148f.png)
[Pytorch study notes] 10. How to quickly create your own Dataset dataset object (inherit the Dataset class and override the corresponding method)

PoE视频监控解决方案
随机推荐
【Kaggle项目实战记录】一个图片分类项目的步骤和思路分享——以树叶分类为例(用Pytorch)
【数据库和SQL学习笔记】5.SELECT查询3:多表查询、连接查询
初识机器学习
Flutter 3.0升级内容,该如何与小程序结合
【数据库和SQL学习笔记】6.SELECT查询4:嵌套查询、对查询结果进行操作
[Intensive reading of the paper] R-CNN's Bounding box regression problem is detailed
A deep learning code base for Xiaobai, one line of code implements 30+ attention mechanisms.
[After a 12] No record for a whole week
【22李宏毅机器学习】课程大纲概述
如何跟踪网络路由链路&检测网络健康状况
flink部署操作-flink on yarn集群安装部署
11%的参数就能优于Swin,微软提出快速预训练蒸馏方法TinyViT
SQL(1) - Add, delete, modify and search
【ts】typescript高阶:联合类型与交叉类型
flink on yarn 集群模式启动报错及解决方案汇总
神经网络也能像人类利用外围视觉一样观察图像
【shell编程】第二章:条件测试语句
基于Flink CDC实现实时数据采集(一)-接口设计
网络信息安全运营方法论 (下)
CAN、CAN FD