当前位置:网站首页>八、响应处理——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~
边栏推荐
猜你喜欢

【Kaggle项目实战记录】一个图片分类项目的步骤和思路分享——以树叶分类为例(用Pytorch)

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

flink基本原理及应用场景分析

【Multisim仿真】直流稳压电源设计报告

CVPR 2022 | 70% memory savings, 2x faster training
![[Kaggle project actual combat record] Steps and ideas sharing of a picture classification project - taking leaf classification as an example (using Pytorch)](/img/7d/7f1301c30034f1c247d41f04c40244.png)
[Kaggle project actual combat record] Steps and ideas sharing of a picture classification project - taking leaf classification as an example (using Pytorch)

CVPR best paper winner Huang Gao's team from Tsinghua University presented the first dynamic network review

【数据库和SQL学习笔记】8.SQL中的视图(view)

原来何恺明提出的MAE还是一种数据增强

IT系统运行维护方法及策略
随机推荐
读论文-Cycle GAN
Flink和Spark中文乱码问题
[Pytorch study notes] 9. How to evaluate the classification results of the classifier - using confusion matrix, F1-score, ROC curve, PR curve, etc. (taking Softmax binary classification as an example)
如何跟踪网络路由链路&检测网络健康状况
【shell编程】第二章:条件测试语句
SharedPreferences and SQlite database
【Pytorch学习笔记】8.训练类别不均衡数据时,如何使用WeightedRandomSampler(权重采样器)
SQL(1) - Add, delete, modify and search
CVPR2020 - 自校准卷积
AWS 常用服务
Day1:用原生JS把你的设备变成一台架子鼓!
关于使用QML的MediaPlayer实现视频和音频的播放时遇到的一些坑
【ts】typescript高阶:typeof使用
数据库期末考试,选择、判断、填空题汇总
网工必用神器:网络排查工具MTR
Oracle压缩表修改字段的处理方法
5G中切片网络的核心技术FlexE
发顶会顶刊论文,你应该这样写作
【数据库和SQL学习笔记】6.SELECT查询4:嵌套查询、对查询结果进行操作
flink on yarn 集群模式启动报错及解决方案汇总