Loading

SpringMVC响应处理原理

上文讲到了SpringMVC是如何解析请求方法中的参数的,这篇文章主要讲一下SpringMVC是如何解析请求方法的返回值的

环境:SpringBoot 2.4.2

我们首先搭建这样的实验环境

@Controller
public class ResponseTestController {

    @ResponseBody
    @GetMapping("/test/person")
    public Person getPerson() {
        Person person = new Person();
        person.setAge(28);
        person.setBirth(new Date());
        person.setUsername("Tom");
        return person;
    }
}

可以看到,在发出请求之后,方法会返回Person类型的json数据。那么,是如何解析出这个返回值的呢

1. 返回值处理器

和前文一样,开启debug,进入DispatcherServlet内真正执行请求方法的代码,直到出现这样的代码

这段代码前文也讲了,现在简单回顾一下。第一个if内部是设置参数解析器,而SpringMVC为我们定义好了27个参数解析器来解析不同的请求方法参数。第二个if内部就是设置返回值处理器,SpringMVC为我们定义好了15个返回值处理器来处理返回值

返回值处理器和参数解析器一样,是一个定义好的接口,它内部只有两个抽象方法,一个是supportsReturnType,判断是否支持返回值,另一个是handleReturnValue,表示对返回值进行处理

另外,和参数解析器一样,请求方法中的参数类型的种类是由参数解析器决定的,那么请求方法的返回值类型的种类也是由返回值处理器决定的

在设置完参数解析器和返回值处理器之后,执行invocableMethod.invokeAndHandle(webRequest, mavContainer);这条语句。在invokeAndHandle方法内部,第一行便是Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);,表示执行完请求方法并得到返回值,而此时这个returnValue便是这个Person实例

而这个方法的其余代码都是对这个returnValue进行处理

处理的时候就会使用到SpringMVC定义好了的返回值处理器

2. 返回值处理器原理

我们step into这一行代码,来到handleReturnValue方法内

在这个方法内,有两个重要的方法,一个是selectHandler,它会根据返回值和返回值类型选择合适的返回值处理器,另一个就是handleReturnValue,对返回值进行处理

2.1 selectHandler

我们进入selectHandler方法内部

方法的主体是一个for循环,也就是挨个遍历寻找支持此返回值的返回值处理器,这个和寻找参数解析器的过程是一样的,只要supportsReturnType返回true,就表示支持返回值

一直循环直到找到RequestResponseBodyMethodProcessor这个返回值处理器,我们可以查看这个处理器的supportsReturnType方法

意思是只要方法的类上标注了@ResponseBody注解或者方法上标注了@ResponseBody注解就支持这个返回值,所以这样就通过selectHandler方法找到了对应的返回值处理器

2.2 handleReturnValue

在找到了支持的返回值处理器之后,就可以使用返回值处理器对返回值进行处理,我们进入handleReturnValue这个方法,因为我们找到的是RequestResponseBodyMethodProcessor这个处理器,所以这个方法是位于这个类中的,方法细节也和其他处理器不同

该方法先对WebRequest进行处理,提取出请求和响应,最后使用MessageConverters消息转换器进行写出操作,得到json数据

2.3 内容协商

writeWithMessageConverters方法内部,有一段代码是表示内容协商部分,内容协商是浏览器告诉服务器能接收的内容类型

在请求头中,浏览器会告诉服务器能够接收的类型和一些规定

其中,acceptableTypes就是浏览器能接收的数据类型

producibleTypes是服务器能响应的数据类型

在知道了浏览器能接收和服务器能响应的类型之后,就是内容协商的主要过程

使用嵌套循环,匹配得到服务器要使用的内容类型

接下来就从服务器要使用的候选内容类型中选择权重最高的作为最终的响应类型

2.4 消息转换

在经过内容协商确定服务器的响应类型之后,就进行消息转换生成最终的数据。消息转换的过程要使用到消息转换器HttpMessageConverter

HttpMessageConverter是一个定义好的接口类型,内部有5个抽象方法

HttpMessageConverter的主要动能就是将特定Class类型的对象转换为特定MediaType类型的数据,比如在本文的实验中,是将Person实例转换为json数据

SpringMVC已经为我们定义好了9个消息转换器

所以,消息转换的过程和使用返回值处理器或者使用参数解析器的过程类似,挨个遍历消息转换器,判断能否支持相应的类型,如果支持,则进行消息转换。在本文的实验中,可以确定MappingJackson2HttpMessageConverter这个消息转换器,最后调用write方法,底层是通过Jackson的ObjectMapper转换得到json数据

3. 总结

在请求方法执行完之后得到返回值,首先从SpringMVC定义好的返回值处理器中选择支持该返回值的ReturnValueHandler返回值处理器,再利用确定的返回值处理器处理返回值。每个返回值处理器对返回值的处理过程各不相同,如果是RequestResponseBodyMethodProcessor这个返回值处理器,在处理返回值的过程中需要先进行内容协商确定需要生成的数据类型,也就是服务器响应的数据类型,那么这个过程就需要HttpMessageConverter消息转换器。SpringMVC已经定义好了多个消息转换器,则从中确定消息转换器的过程和确定返回值处理器的过程是类似的,确定好了之后,就使用特定的消息转换器进行消息转换得到json数据

posted @ 2021-02-09 18:20  Kinopio  阅读(306)  评论(0编辑  收藏  举报