Spring MVC序列化流程

3,893 阅读1分钟

使用 Spring MVC 进行开发的时候,如果想返回 json 格式的数据,只需要添加在 controller 的方法上添加 @ResponseBody 注解,Spring 就会自动将 bean 转成 json。

@Controller
@RequestMapping(value = "/test")
public class TestController {

    @ResponseBody
    @GetMapping("")
    public User test() {
        return new User("张三", 20);
    }
}

请求http://127.0.0.1:8080/test后的返回结果

{
    "name": "张三",
    "age": 20
}

那序列化过程是如何实现的呢?通过 DEBUG 代码,发现序列化过程如下:

首先调用 ServletInvocableHandlerMethod 里面的 invokeAndHandle 方法,在 invokeAndHandle 方法中会通过 invokeForRequest 方法获取到需要返回的对象 returnValue,然后再调用 this.returnValueHandlers.handleReturnValue 方法来处理返回值。

上面的 handleReturnValue 方法中会先调用 selectHandler 方法,通过遍历 returnValueHandlers List 来判断返回类型是否是支持的类型,从而找到到合适的 HandlerMethodReturnValueHandler 的实现类,

其中 supportsReturnType 方法会判断当前这个返回类型的 controller 方法是否含有 @ResponseBody 注解。

我这里的例子是调用其实现类之一的 RequestResponseBodyMethodProcessor 类的 handleReturnValue 方法,然后再调用 writeWithMessageConverters

然后,根据返回的MediaType类型,选择合适的 HttpMessageConverter 实现类调用其 write 方法来实现序列化。

write 方法又调用了 writeInternal 方法来获取 objectWriter,通过 objectWriter.writeValue 方法 实现序列化。

   protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        MediaType contentType = outputMessage.getHeaders().getContentType();
        JsonEncoding encoding = this.getJsonEncoding(contentType);
        JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);

        try {
            this.writePrefix(generator, object);
            Class<?> serializationView = null;
            FilterProvider filters = null;
            Object value = object;
            JavaType javaType = null;
            if (object instanceof MappingJacksonValue) {
                MappingJacksonValue container = (MappingJacksonValue)object;
                value = container.getValue();
                serializationView = container.getSerializationView();
                filters = container.getFilters();
            }

            if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
                javaType = this.getJavaType(type, (Class)null);
            }

            ObjectWriter objectWriter;
            if (serializationView != null) {
                objectWriter = this.objectMapper.writerWithView(serializationView);
            } else if (filters != null) {
                objectWriter = this.objectMapper.writer(filters);
            } else {
                objectWriter = this.objectMapper.writer();
            }

            if (javaType != null && javaType.isContainerType()) {
                objectWriter = objectWriter.forType(javaType);
            }

            SerializationConfig config = objectWriter.getConfig();
            if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) && config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
                objectWriter = objectWriter.with(this.ssePrettyPrinter);
            }

            objectWriter.writeValue(generator, value);
            this.writeSuffix(generator, object);
            generator.flush();
        } catch (InvalidDefinitionException var13) {
            throw new HttpMessageConversionException("Type definition error: " + var13.getType(), var13);
        } catch (JsonProcessingException var14) {
            throw new HttpMessageNotWritableException("Could not write JSON: " + var14.getOriginalMessage(), var14);
        }
    }