SpringMVC之json是怎么传回前端的 @ResponseBody解析
一 序章
http的请求里有一个属性叫accept,它规定了返回值类型,本篇要讲的返回值正是跟这个属性关系紧密
二 源码分析
SpringMVC为@RequestBody和@ResponseBody两个注解实现了统一处理类RequestResponseBodyMethodProcessor,实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler两个接口。
ServletInvocableHandlerMethod
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); //今天只看这部分 } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } }
要执行就离不开 returnValueHandlers 。先讲讲这些 returnValueHandlers 怎么初始化的
我们先看 RequestMappingHandlerAdapter.invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);//设置返回值Handler invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
注意这里,每次处理请求的时候,把原始HandlerMethod包装成一个 ServletInvocableHandlerMethod,这里用的是每次都new一个出来
protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) { return new ServletInvocableHandlerMethod(handlerMethod); }
所以就来看看 RequestMappingHandlerAdapter里的 returnValueHandlers 是怎么来的
现在已经知道了 RequestMappingHandlerAdapter 会被当成一个bean来进行初始化,而且它还实现了 InitializingBean
@Override public void afterPropertiesSet() { // Do this first, it may add ResponseBody advice beans initControllerAdviceCache(); if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } }
这个getDefaultReturnValueHandlers很长,这里就不贴了,只需要记住一条 RequestResponseBodyMethodProcessor 也是 这个handlers中的一员。而它恰恰是处理@ResponseBody的关键
现在回头继续看 his.returnValueHandlers.handleReturnValue
HandlerMethodReturnValueHandlerComposite
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }
这里就是选择合适的handler,因为我们的返回值是有@ResponseBody注解的,所以就选出来了 RequestResponseBodyMethodProcessor
RequestResponseBodyMethodProcessor
public boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); }
最终会调用 AbstractMessageConverterMethodProcessor.writeWithMessageConverters
这个方法很长,这里只看一部分。如果返回值是一个引用类型而不是基础类型,那就要有jackson相关的类,在这里 messageConverter 就是 MappingJackson2HttpMessageConverter , 在这里调用write方法就对对象做了序列化,在通过HttpResponse的outputStream写出去
if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> messageConverter : this.messageConverters) { if (messageConverter instanceof GenericHttpMessageConverter) { if (((GenericHttpMessageConverter) messageConverter).canWrite( declaredType, valueType, selectedMediaType)) { outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage); if (outputValue != null) { addContentDispositionHeader(inputMessage, outputMessage); ((GenericHttpMessageConverter) messageConverter).write( outputValue, declaredType, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]"); } } return; } }
上面的 outputMessage 类型是 HttpOutputMessage
public interface ServerHttpResponse extends HttpOutputMessage, Flushable, Closeable
HttpResponse正是其子类,最终推送给前端还是要靠response