-
前面说了适配器执行 handler 怎么解析请求参数,现在看怎么响应参数,还是从具体执行 handler 的方法开始
// org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 这里在解析参数,并拿到了方法的返回值 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); ... try { // 这里处理方法返回值,先获取返回值的处理对象 this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
-
怎么拿返回值处理对象。逻辑和处理器映射器、处理器适配器、参数解析器、参数消息转换器一致,都是挨个遍历,看哪个合适
// org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue @Override public void handleReturnValue(@Nullable 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); } // org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#selectHandler @Nullable private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); // 看过太多这种逻辑了,都是遍历,找到一个合适的 for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } // 这里可以进去看下,最终是选择了 RequestResponseBodyMethodProcessor,为什么是它?看看 supportsReturnType 方法就知道了 if (handler.supportsReturnType(returnType)) { return handler; } } return null; } // org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#supportsReturnType @Override public boolean supportsReturnType(MethodParameter returnType) { // 使用了 @ResponseBody 的注解就使用 RequestResponseBodyMethodProcessor 来处理 return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); }
-
现在知道了 @ResponseBody 的注解就使用 RequestResponseBodyMethodProcessor 来处理,具体怎么处理?
// org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue @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); // 转型并写入响应流(根据源码是先获取 HttpMessageConvert 然后再转型,最后写入流) writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
-
拿 HttpMessageConvert 同请求参数解析一样,也要看 content-type 等一系列校验才能拿到合适的 HttpMessageConvert
源码太多,只保留关键信息,把些判断都删掉,参数解析那里留下的源码多些,可以去那里看
// org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse) protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { // 巴拉巴拉,王八念经 if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> converter : this.messageConverters) { GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); // 这里和参数解析一样,判断 if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage); if (body != null) { Object theBody = body; LogFormatUtils.traceDebug(logger, traceOn -> "Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]"); addContentDispositionHeader(inputMessage, outputMessage); if (genericConverter != null) { // 调用 HttpMessageConvert 的些操作,把数据写入响应流 genericConverter.write(body, targetType, selectedMediaType, outputMessage); } else { ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage); } } else { if (logger.isDebugEnabled()) { logger.debug("Nothing to write: null body"); } } return; } } } }
贴个图便于理解
-
有了 HttpMessageConvert,这时开始转型和写入流
// org.springframework.http.converter.GenericHttpMessageConverter#write @Override public final void write(final T t, @Nullable final Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { final HttpHeaders headers = outputMessage.getHeaders(); addDefaultHeaders(headers, t, contentType); if (outputMessage instanceof StreamingHttpOutputMessage) { StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage; streamingOutputMessage.setBody(outputStream -> writeInternal(t, type, new HttpOutputMessage() { @Override public OutputStream getBody() { return outputStream; } @Override public HttpHeaders getHeaders() { return headers; } })); } else { // 这个方法又调用了本类的 writeInternal,本类的 writeInternal 又是个模板方法,所以到子类去看实现,然后就到了 jackson 了 // 这个方法的作用是转型,方法体在下面 writeInternal(t, type, outputMessage); // 刷新响应流,over outputMessage.getBody().flush(); } } // org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter#writeInternal @Override protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { MediaType contentType = outputMessage.getHeaders().getContentType(); JsonEncoding encoding = getJsonEncoding(contentType); JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding); try { ... // 这里在进行些操作,也就是 jackson 的转型操作,有兴趣可以看看自行去 jackson 怎么做的,但本次的 @ResponseBody 原理已经结束了 objectWriter.writeValue(generator, value); writeSuffix(generator, object); generator.flush(); } catch (InvalidDefinitionException ex) { throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex); } catch (JsonProcessingException ex) { throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex); } }