首页
学习
活动
专区
圈层
工具
发布

SpringFramework之HandlerMethodReturnValueHandler

    SpringFramework版本是5.1.9

List-1

代码语言:javascript
复制
@Controller
public class UserController {

    @RequestMapping("/user")
    @ResponseBody
    public User user(){
        System.out.println("收到请求");
        User alen = new User("Alen", 25);
        return alen;
    }
}

...

public class User {
    private String name;
    private int age;
...

    如上所示List-1,springboot中这样使用后,会返还json数据,那么spring是怎么将User序列化后写入response的呢?

    DispatcherServlet的doDispatch方法中,调用HandlerAdapter.handle方法,

    AbstractHandlerMethodAdapter#handle->RequestMappingHandlerAdapter#handleInternal->invokeHandlerMethod

        ->ServletInvocableHandlerMethod#invokeAndHandle

List-2

代码语言:javascript
复制
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
        Object... providedArgs) throws Exception {
    //调用controller的方法得到User
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    setResponseStatus(webRequest);

    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            disableContentCachingIfNecessary(webRequest);
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }

    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        //调用ReturnValueHandler
        this.returnValueHandlers.handleReturnValue(
                returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(formatErrorForReturnValue(returnValue), ex);
        }
        throw ex;
    }
}

    如List-2所示

  •     invokeForRequest方法使用反射调用UserController.user方法,得到User对象
  •     之后调用returnValueHandlers.handleReturnValue方法,这个方法里面就是将User对象写入response流中

List-3

代码语言:javascript
复制
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

    如List-3所示,HandlerMethodReturnValueHandlerComposite,看到这个类名称,就知道使用了组合模式,不用说这个类的内部一定有一个集合来存储HandlerMethodReturnValueHandler。

    来看HandlerMethodReturnValueHandlerComposite的handleReturnValue方法

List-4

代码语言:javascript
复制
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    } else {
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }
}

@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
    ...
    Iterator var4 = this.returnValueHandlers.iterator();

    HandlerMethodReturnValueHandler handler;
    do {
        ...
    } while(!handler.supportsReturnType(returnType));

    return handler;
}

    如上List-4

  • returnValueHandlers的类型是List<HandlerMethodReturnValueHandler>
  • 循环遍历returnValueHandlers,看哪个handler支持处理这种返回类型,即handler.supportsReturnType()
  • 调用HandlerMethodReturnValueHandler.handleReturnValue来处理UserController的返还结果

    HandlerMethodReturnValueHandler的实现类有15种,List-1中的情况使用哪个HandlerMethodReturnValueHandler呢? 

    是RequestResponseBodyMethodProcessor,我们来看它的supportsReturnType方法和handleReturnValue方法

List-5

代码语言:javascript
复制
@Override
public boolean supportsReturnType(MethodParameter returnType) {
    return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
            returnType.hasMethodAnnotation(ResponseBody.class));
}

...

@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
        ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
        throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

    mavContainer.setRequestHandled(true);
    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

    // Try even with null return value. ResponseBodyAdvice could get involved.
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

...

protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequest) {
    HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
    Assert.state(response != null, "No HttpServletResponse");
    return new ServletServerHttpResponse(response);
}

    如上List-5

  • supportsReturnType方法中,AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class)判断UserController类上有没有ResponseBody注解,@RestController注解就是@Controller和@ResponseBody注解的组合,所以只要Controller类上有@RestController注解,就会由这行类来处理
  • supportsReturnType方法中,returnType.hasMethodAnnotation(ResponseBody.class)判断user()方法上是否有@ResponseBody注解,由于UserController.user方法上有ResponseBody注解,所以这个方法返还true

    handleReturnValue方法中,

  • 调用createOutputMessage方法,获取ServletServerHttpResponse
  • 之后在writeWithMessageConverters中将User对象序列化后输出到response流中

    writeWithMessageConverters方法中,使用到HttpMessageConverter,用HttpMessageConverter来将User对象序列化,具体实现类是MappingJackson2HttpMessageConverter。writeWithMessageConverters方法内部还是和HandlerMethodReturnValueHandlerComposite一样使用到了组合,然后使用Template设计模式,所以有的人使用Fastjson来做序列化时就是自定义了HttpMessageConverter的实现,然后注册到spring容器中

    一些思考,spring中有ViewResolver用来将结果渲染为页面,但是rest接口是不由ViewResolver来处理的,所以在ViewResolver那打断点,程序还没执行到那,但是结果已经返还到客户端了。

下一篇
举报
领券