SpringBoot2:请求处理原理分析-接口方法的返回值处理(returnValueHandlers)

一、知识回顾

前面,我们学习了,一个请求过来,先经过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默认是从requestHeaders中,获取Accept参数值,作为媒体类型,进行内容协商。
其实,也可以从参数中获取。
后面给出案例。

2、找到具体的消息转换器(HttpMessageConverter)。
springboot默认配置了10种消息转换器。
Java对象write给浏览器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值