SpringFramework之HandlerMethodReturnValueHandler

编程

    SpringFramework版本是5.1.9

    List-1

@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

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

private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

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

    来看HandlerMethodReturnValueHandlerComposite的handleReturnValue方法

    List-4

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

@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那打断点,程序还没执行到那,但是结果已经返还到客户端了。

以上是 SpringFramework之HandlerMethodReturnValueHandler 的全部内容, 来源链接: utcz.com/z/517313.html

回到顶部