在 SpringMVC 工作原理三(参数解析器)-优快云博客 一文中,我们分析了 Spring MVC 如何将请求中的参数解析为调用目标方法的参数,然后利用反射调用目标方法获得返回值;那么在目前普遍为前后端分类的开发场景中,Spring MVC 是如何将标注了 @ResponseBody或 @RestController 注解的方法返回数据格式转换为 JSON 格式的,这是本文将分析的。
1. 标注 @RestController 注解的方法返回
@RestController
public class BasicController {
// http://127.0.0.1:8080/user
@GetMapping("/user")
public User user() {
User user = new User();
user.setName("theonefx");
user.setAge(666);
return user;
}
}
2. ServletInvocableHandlerMethod 的 invokeAndHandle 方法
之前我们了解过 HandlerMethod 有两个子类:
- InvocableHandlerMethod:类中 resolvers 属性保存所有参数解析器,所以包含通过 参数解析器 解析参数和调用目标方法获取返回值的逻辑。
- ServletInvocableHandlerMethod:类中 returnValueHandlers 属性保存所有返回值处理器,所以包含通过 返回值处理器 处理返回值的逻辑。
3. HandlerMethodReturnValueHandler 接口
所有 返回值处理器 实现自此接口,实现 handleReturnValue 方法来处理返回值。
4. ServletInvocableHandlerMethod 的 returnValueHandlers 属性
ServletInvocableHandlerMethod 的 returnValueHandlers 属性保存了 HandlerMethodReturnValueHandlerComposite 类的对象,而 HandlerMethodReturnValueHandlerComposite 类的 returnValueHandlers 属性才真正保存了所有返回值处理器,并且此类实现了 handleReturnValue 方法来处理返回值。
5. 返回值处理器之一的 RequestResponseBodyMethodProcessor
RequestResponseBodyMethodProcessor 主要用来处理 @ResponseBody 或 @RequestBody 注解的返回值,通过消息转换器(如JSON转换器)序列化响应体。
5.1 supportsReturnType 方法
通过检测控制器方法(或其所在类)是否被 @ResponseBody 注解标记。若存在该注解,则返回 true。
5.2 handleReturnValue 方法
利用 MessageConverters 将返回数据写为 JSON 格式
5.3 writeWithMessageConverters 方法
此方法太长,只能分开几个过程来分析;
5.3.1 判断返回值类型
5.3.2 获取浏览器能够接收的媒体类型和服务能够提供的媒体类型
5.3.3 确认最终的媒体类型
5.3.4 利用 HttpMessageConverter 消息转换器将返回值转换为最终确认的媒体类型
最终 MappingJackson2HttpMessageConverter 利用 Jackson 的 ObjectMapper 将对象转为 JSON 格式。
6.消息转换器接口 HttpMessageConverter
- canRead:判断当前转换器是否能够将 HTTP 请求体(如 JSON、XML 数据)读取为指定的 Java 类型。
- canWrite:判断当前转换器是否能够将指定的 Java 类型写入为 HTTP 响应体(如生成 JSON、XML 数据)。
- read:将 HTTP 请求体(输入流)读取并转换为指定类型的 Java 对象。
- write:将 Java 对象写入到 HTTP 响应体中,并设置对应的媒体类型。