• 【SpringBoot】响应处理——数据以 json 格式返回的原理


    一、示例代码:

    访问 localhost:8080/jsonTest —— 返回 json 格式的数据

    @Controller
    public class ResponseTestController {
        @ResponseBody // 标注 —— 自动返回json数据
        @GetMapping("/jsonTest")
        public Person testPerson(){
            Person person = new Person();
            person.setAge(20);
            person.setUserName("Liuwanqing");
            Pet pet = new Pet();
            pet.setName("huahua");
            pet.setAge("五个月");
            person.setPet(pet);
            return person;
        }
    }
    
    二、返回值解析原理

    SpringBoot 支持的返回值类型是由返回值解析器决定的,SpringBoot 返回值类型如下:

    ModelAndView
    Model
    View

    SpringBoot共含15种返回值解析器决定了其支持15种返回值:
    在这里插入图片描述

    三、源代码分析(debug)

    设置以下几处断点:
    在这里插入图片描述

    step into —— 返回值处理器逻辑
                this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
    

    1. 先找返回值处理器

            HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
    

    2. 执行下列代码,找到符合要求的返回值处理器
    在众多返回值处理器中找到符合要求的 —RequestResponseBodyMethodRrocessor
    即 RequestResponseBodyMethodRrocessor 可处理标注了 @ResponseBody 注解的返回值

       private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
            boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);
            Iterator var4 = this.returnValueHandlers.iterator();
    
            HandlerMethodReturnValueHandler handler;
            do {
                do {
                    if (!var4.hasNext()) {
                        return null;
                    }
    
                    handler = (HandlerMethodReturnValueHandler)var4.next();
                } while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));
            } while(!handler.supportsReturnType(returnType));
    
            return handler;
        }
    

    在这里插入图片描述
    3. 调用返回值处理器(interface HandlerMethodReturnValueHandler)处理:
    判断是否支持这种类型的返回值,支持调用返回值处理器,调用 handleReturnValue 进行处理

    public interface HandlerMethodReturnValueHandler {
        boolean supportsReturnType(MethodParameter var1);
    
        void handleReturnValue(@Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception;
    }
    

    4. RequestResponseBodyMethodRrocessor工作原理
    关键代码:

        public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
            mavContainer.setRequestHandled(true);
            ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
            ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
            this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
        }
    

    处理返回值的方法
    使用消息转换器(涉及内容协商机制,请移步下文内容协商机制)进行写出操作,消息转换器工作过程如下:

    1. 浏览器告知服务器其处理能力
    2. 服务器根据其自身能力,判断服务器能生产什么样的内容
    3. SpringMVC 遍历所有容器的底层 HttpMessageConverter, 看谁能处理


    四、内容协商机制

    1. 内容协商: 浏览器告知服务器其需要什么类型的服务类型

    浏览器可接受的类型:在这里插入图片描述服务器得到浏览器的处理能力:在这里插入图片描述服务器将返回内容转为浏览器能处理的形式在这里插入图片描述

    2. 内容协商原理重点源代码

       protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, @Nullable Type targetType) {
            Set<MediaType> mediaTypes = (Set)request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
            if (!CollectionUtils.isEmpty(mediaTypes)) {
                return new ArrayList(mediaTypes);
            } else if (this.allSupportedMediaTypes.isEmpty()) {
                return Collections.singletonList(MediaType.ALL);
            } else {
                List<MediaType> result = new ArrayList();
                Iterator var6 = this.messageConverters.iterator();
    
                while(true) {
                    while(var6.hasNext()) {
                        HttpMessageConverter<?> converter = (HttpMessageConverter)var6.next();
                        if (converter instanceof GenericHttpMessageConverter && targetType != null) {
                            if (((GenericHttpMessageConverter)converter).canWrite(targetType, valueClass, (MediaType)null)) {
                                result.addAll(converter.getSupportedMediaTypes());
                            }
                        } else if (converter.canWrite(valueClass, (MediaType)null)) {
                            result.addAll(converter.getSupportedMediaTypes());
                        }
                    }
    
                    return result;
                }
            }
        }
    
    3. HttpMessageConverters消息转换器原理
    1. MessageConverter 规范
      在这里插入图片描述

    2. 默认的MessageConverter
      在这里插入图片描述

    3. 最终 MappingJackson2HttpMessageConverter 把对象转为JSON(利用底层的jackson的objectMapper转换的)

    总结:
    1. 返回值处理器判断是否支持这种类型的返回值( supportsReturnType)
    2. 返回值处理器调用handleReturnValue 进行处理
    3. 以 @ResponseBody 注解为例,RequestResponseBodyMethodProcessor 可以处理返回值标
    4. 最后,利用 MessageConverters 进行处理 将数据写为json

    尾注: 我是真的不想看SpringBoot源码, 属实是有点强人所难了

  • 相关阅读:
    IAP固件升级进阶(Qt上位机)
    【C语言学习笔记---字符串函数】
    【游戏建模全流程】Maya制作绿色小屋模型
    MTK6877/MT6877天玑900安卓5G核心板_安卓开发板主板定制开发
    多层固定分组计算
    Unity Mirror学习(一) SyncVars属性使用
    静态双位置继电器GLS-3004K/DC220V
    大一作业HTML网页作业:中华传统文化题材网页设计5页(纯html+css实现)
    C# WPF入门学习主线篇(三十三)—— 使用ICommand实现命令绑定
    [网络工程师]-应用层协议-DNS
  • 原文地址:https://blog.csdn.net/liuwanqing233333/article/details/127090965