HandlerMethodReturnValueHandler处理返回值

243 阅读4分钟

springmvc是如何对返回值进行响应的,控制器如何区分返回的是json数据or视图。实现这个过程主要依靠的是返回值处理器HandlerMethodReturnValueHandler,HandlerMethodReturnValueHandler是接口,

supportsReturnType:判断返回值类型当前处理器是否能处理

handleReturnValue:如果当前处理器支持处理这个类型,将会调用这个方法对返回值进行处理

public interface HandlerMethodReturnValueHandler {

   /**
    * Whether the given {@linkplain MethodParameter method return type} is
    * supported by this handler.
    * @param returnType the method return type to check
    * @return {@code true} if this handler supports the supplied return type;
    * {@code false} otherwise
    */
   boolean supportsReturnType(MethodParameter returnType);

   /**
    * Handle the given return value by adding attributes to the model and
    * setting a view or setting the
    * {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}
    * to indicate the response has been handled directly.
    * @param returnValue the value returned from the handler method
    * @param returnType the type of the return value. This type must have
    * previously been passed to {@link #supportsReturnType} which must
    * have returned {@code true}.
    * @param mavContainer the ModelAndViewContainer for the current request
    * @param webRequest the current request
    * @throws Exception if the return value handling results in an error
    */
   void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
         ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

}

ServletInvocableHandlerMethod:对目标方法的调用最终都会被包装成ServletInvocableHandlerMethod对象进行方法调用

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {
   // 调用目标controller方法,returnValue就是controller的返回值
   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 {
      // 根据返回值类型,选择合适的处理器进行处理
      this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
   }
   catch (Exception ex) {
      if (logger.isTraceEnabled()) {
         logger.trace(formatErrorForReturnValue(returnValue), ex);
      }
      throw ex;
   }
}

ServletInvocableHandlerMethod对象中维护着容器着已经存在的处理器

@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

HandlerMethodReturnValueHandlerComposite运用了组合的设计模式,会委托给具体的返回值处理器,每个返回值处理器会根据返回值类型自行判断是否支持处理返回值

// 自身实现了HandlerMethodReturnValueHandler接口,同时内部维护着一个处理器列表,委托给具体的处理器进行处理
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {

   // 处理器列表
   private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();


   /**
    * Return a read-only list with the registered handlers, or an empty list.
    */
   public List<HandlerMethodReturnValueHandler> getHandlers() {
      return Collections.unmodifiableList(this.returnValueHandlers);
   }

   /**
    * Whether the given {@linkplain MethodParameter method return type} is supported by any registered
    * {@link HandlerMethodReturnValueHandler}.
    */
   @Override
   public boolean supportsReturnType(MethodParameter returnType) {
      return getReturnValueHandler(returnType) != null;
   }

   // 遍历所有的返回值处理器,选择一个能支持的进行返回处理
   @Nullable
   private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
      for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
         if (handler.supportsReturnType(returnType)) {
            return handler;
         }
      }
      return null;
   }

   /**
    * Iterate over registered {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers} and invoke the one that supports it.
    * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
    */
   @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);
   }
 }  
   
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
      implements HandlerMethodReturnValueHandler 

如上图所示RequestResponseBodyMethodProcessor继承AbstractMessageConverterMethodProcessor,最终实现了HandlerMethodReturnValueHandler,所以RequestResponseBodyMethodProcessor有能力去处理返回值,RequestResponseBodyMethodProcessor

判断2点,满足一下两点之一,表明支持处理该返回值

  • 参数所在类上有没有@ResponseBody注解
  • 参数所在方法上或返回值上是否标注了@ResponseBody注解
@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 {
   // 设置请求已被处理
   // ModelAndViewContainer中有个requestHandled字段用来标识请求是否被处理
   mavContainer.setRequestHandled(true);
   // 将原始的请求对象包装为ServletServerHttpRequest
   ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
   // 将原始的响应对象包装为ServletServerHttpResponse
   ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
   // Try even with null return value. ResponseBodyAdvice could get involved.
   // 将返回值写入响应体输出流中
   writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

writeWithMessageConverters 会调用messageConverter将消息转化成指定的格式

public interface GenericHttpMessageConverter<T> extends HttpMessageConverter<T> {

   /**
    * Indicates whether the given type can be read by this converter.
    */
   boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType);

   /**
    * Read an object of the given type form the given input message, and returns it.
    */
   T read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
         throws IOException, HttpMessageNotReadableException;

   /**
    * Indicates whether the given class can be written by this converter.
    */
   boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType);

   /**
    * Write an given object to the given output message.
    */
   void write(T t, @Nullable Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
         throws IOException, HttpMessageNotWritableException;

}

最后选择MappingJackson2HttpMessageConverter将输出转化成json字符串写入到输出流中返回

public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter

总结: 1.dispatchServlert会将调用的方法包装成ServletInvocableHandlerMethod对象进行调用

2.调用的结果选择合适的返回值处理器HandlerMethodReturnValueHandler处理

3.由于使用了responsebody注解,所以RequestResponseBodyMethodProcessor处理可以处理返回值

4.RequestResponseBodyMethodProcessor内部使用messageConverter进行处理,将数据返回。

这就是加上一个responsebody注解就能返回json的原因。

接下来会聊一聊

1:内容协商的过程

2:视图解析的过程

3:本文并没有对messageConverter进行仔细的讲解,后续会展开如何借助jackson将json返回前端