当前位置:网站首页>八、响应处理——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~
边栏推荐
- The difference between the operators and logical operators
- 【论文精读】ROC和PR曲线的关系(The relationship between Precision-Recall and ROC curves)
- [Practice 1] Diabetes Genetic Risk Detection Challenge [IFLYTEK Open Platform]
- 【数据库和SQL学习笔记】10.(T-SQL语言)函数、存储过程、触发器
- 【Pytorch学习笔记】10.如何快速创建一个自己的Dataset数据集对象(继承Dataset类并重写对应方法)
- [Pytorch study notes] 10. How to quickly create your own Dataset dataset object (inherit the Dataset class and override the corresponding method)
- 【Pytorch学习笔记】11.取Dataset的子集、给Dataset打乱顺序的方法(使用Subset、random_split)
- CVPR最佳论文得主清华黄高团队提出首篇动态网络综述
- MySql之索引
- 网管日记:故障网络交换机快速替换方法
猜你喜欢
Tensorflow2 与 Pytorch 在张量Tensor基础操作方面的对比整理汇总
CVPR2021 - Inception Convolution with Efficient Dilation Search
读论文 - Unpaired Portrait Drawing Generation via Asymmetric Cycle Mapping
[Database and SQL study notes] 8. Views in SQL
MSRA proposes extreme masking model ExtreMA for learning instances and distributed visual representations
WCH系列芯片CoreMark跑分
Tensorflow踩坑笔记,记录各种报错和解决方法
ECCV2022 | RU & Google propose zero-shot object detection with CLIP!
数控直流电源
Facial Motion Capture 调研
随机推荐
网络信息安全运营方法论 (中)
dataframe 常用操作
[Go through 11] Random Forest and Feature Engineering
SharedPreferences and SQlite database
ECCV2022 | RU&谷歌提出用CLIP进行zero-shot目标检测!
OSPF故障排除办法
【ts】typescript高阶:typeof使用
数据库期末考试,选择、判断、填空题汇总
数控直流电源
The University of Göttingen proposed CLIPSeg, a model that can perform three segmentation tasks at the same time
【数据库和SQL学习笔记】8.SQL中的视图(view)
关于使用QML的MediaPlayer实现视频和音频的播放时遇到的一些坑
Flink EventTime和Watermarks案例分析
MaskDistill - Semantic segmentation without labeled data
Thread handler句柄 IntentServvice handlerThread
[Intensive reading of the paper] R-CNN's Bounding box regression problem is detailed
华科提出首个用于伪装实例分割的一阶段框架OSFormer
网络ID,广播地址,掩码位数计算
【论文精读】R-CNN 之预测框回归(Bounding box regression)问题详述
解决:Unknown column ‘id‘ in ‘where clause‘ 问题