一、知识回顾
前面,我们学习了,一个请求过来,先经过filter组件,判断restful风格接口的请求类型。
然后,通过HandlerMapping找到处理该请求的接口。
接着,进入接口方法的参数解析环节,这里主要学习了参数解析器(argumentResolvers)
和数据类型转换服务(Converters),将请求的实参值与方法的形参绑定上。
然后,执行接口方法主体。
那么,方法体执行完后,就到了return环节。就是返回值处理环节。
这一篇,我们就来看一下返回值处理的源码逻辑。
二、测试接口
接下来,我们就对@ResponseBody标注的接口,进行返回值原理探究。
@ResponseBody //利用返回值处理器里面的消息转换器进行处理
@GetMapping(value = "/test/person")
public Person getPerson(){
Person person = new Person();
person.setAge(28);
person.setBirth(new Date());
person.setUserName("zhangsan");
return person;
}

我们知道,@ResponseBody标注的接口,都会给页面返回json数据。
三、源码解读
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

这里,我们看到了返回值处理器,默认是15个。

中间的其他步骤,我直接跳过了,进入关键代码
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue

这里,第一步,先获取能处理这个接口返回值类型的返回值处理器。这个获取逻辑,就是从15个返回值处理器中,循环遍历,找到具体的返回值处理器。

我们查看下返回值处理器接口规范

两个方法
supportsReturnType:判断方法
handleReturnValue:处理逻辑
会发现,这个设计模式和参数解析器一样思路。
断点放行下一步,得到@ResponseBody标注的接口的返回值处理器是:
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue

这个返回值处理方法,我们可以看到,最后一行的方法名
利用消息转换器写数据。
所以,返回值处理器,需要依赖底层的消息转换器。
我们在看下消息转换器的具体逻辑
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)

这里又出现一个新的组件,媒体类型。
媒体类型:就是请求接口的客户端,如浏览器,postman,传给接口的Accept参数值。
目的就是告诉服务器接口,我能接收那些类型的返回值。
让springboot根据权重,选择最佳返回值返回给浏览器。

那么,这里就涉及到springboot接口能生产那些类型的返回值。
然后,才能选择最优解。
这个选择过程,就叫内容协商。
内容协商:说简单点,就是,浏览器和服务器商量,用什么样的结构数据返回给浏览器。
继续往下看

这里,我们获取到了,所有浏览器可以接收的返回值类型,和所有springboot可以生产的返回值类型
接下来,就要利用嵌套for循环确定出最终返回值类型。


经过循环处理后,得到14个可以返回的数据类型,并对这14个类型进行了权重排序。
m.m.a.RequestResponseBodyMethodProcessor : Using 'application/json;q=0.8', given [text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.7, */*;q=0.8] and supported [application/json, application/*+json, application/json, application/*+json]
从日志看出,最终协商结果就是,返回json数据格式。
内容协商阶段结束后,就要利用消息转换器(HttpMessageConverter),进行返回值数据格式化了。
把Java对象,处理成json结构,返回给浏览器。


springboot默认的消息转换器有10中。
那么,哪个消息转换器负责处理json返回值了?
这里,我们依然看一下消息转换器接口规范

有5个待实现的方法。

最终,是
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
来处理json返回类型的数据。
调用对应的write方法,写出json数据给浏览器。
到这里,返回值处理的过程和主要组件介绍完毕。
四、逻辑梳理
简单来说就是以下几步:
首先,请求过来后,DispatcherServlet中,会确定返回值处理器returnValueHandlers。
默认有15种。
然后,具体的返回值处理器来进行处理。
返回值处理器中的逻辑如下
1、进行内容协商。
获取客户端发过来的能接收的所有媒体类型(MediaType)。
评估自己能生产的所有数据类型(ProducibleMediaTypes)
springboot默认是从request的Headers中,获取Accept参数值,作为媒体类型,进行内容协商。
其实,也可以从参数中获取。
后面给出案例。
2、找到具体的消息转换器(HttpMessageConverter)。
springboot默认配置了10种消息转换器。
将Java对象write给浏览器。
3711

被折叠的 条评论
为什么被折叠?



