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