【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---一篇文章带你读懂返回值处理器HandlerMethodReturnValueHandler (下)

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---一篇文章带你读懂返回值处理器HandlerMethodReturnValueHandler (下)

AsyncHandlerMethodReturnValueHandler


它是一个子接口,增加了一个方法。这个接口是Spring4.2提供的,挺有意思的一个接口,Spring内部并没有提供任何实现。


// @since 4.2
// 支持异步类型的返回值处理程序。此类返回值类型需要优先处理,以便异步值可以“展开”。
// 异步实现此接口并不是必须的,但是若你需要在处理程序之前执行,就需要实现这个接口了~~~
// 因为默认情况下:我们自定义的Handler它都是在内置的Handler后面去执行的~~~~
public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodReturnValueHandler {
  // 给定的返回值是否表示异步计算
  boolean isAsyncReturnValue(@Nullable Object returnValue, MethodParameter returnType);
}


需要注意的是,这个接口和异步好像并没有任何关系,只是体现出了它的优先级。


因为默认情况下我们定义custom自己的处理器,排名都是靠后的。但是如果你定义了一个实现类,实现的是AsyncHandlerMethodReturnValueHandler这个子接口,你的排名就会靠前执行了~~~


由于上面已有类似的例子了,此处就不花篇幅举例了。


关于Spring MVC异步处理的几个返回值处理器


因为Spring MVC支持多种异步返回的方式,因此放在此处一起讲。推荐先参考博文:

【小家Spring】高性能关键技术之—体验Spring MVC的异步模式(Callable、WebAsyncTask、DeferredResult) 基础使用篇


StreamingResponseBodyReturnValueHandler

Spring4.2才出来。(因为StreamingResponseBody是Spring4.2才出来的~~~它很方便做文件下载)


public class StreamingResponseBodyReturnValueHandler implements HandlerMethodReturnValueHandler {
  // 显然这里支持返回值直接是StreamingResponseBody类型,也支持你用`ResponseEntity`在包一层
  // ResponseEntity的泛型类型必须是StreamingResponseBody类型~~~
  @Override
  public boolean supportsReturnType(MethodParameter returnType) {
    if (StreamingResponseBody.class.isAssignableFrom(returnType.getParameterType())) {
      return true;
    } else if (ResponseEntity.class.isAssignableFrom(returnType.getParameterType())) {
      Class<?> bodyType = ResolvableType.forMethodParameter(returnType).getGeneric().resolve();
      return (bodyType != null && StreamingResponseBody.class.isAssignableFrom(bodyType));
    }
    return false;
  }
  @Override
  @SuppressWarnings("resource")
  public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    // 从这句代码也可以看出,只有返回值为null了,它才关闭,否则可以持续不断的向response里面写东西
    if (returnValue == null) {
      mavContainer.setRequestHandled(true);
      return;
    }
    HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
    Assert.state(response != null, "No HttpServletResponse");
    ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
    // 从ResponseEntity里body提取出来~~~~~
    if (returnValue instanceof ResponseEntity) {
      ResponseEntity<?> responseEntity = (ResponseEntity<?>) returnValue;
      response.setStatus(responseEntity.getStatusCodeValue());
      outputMessage.getHeaders().putAll(responseEntity.getHeaders());
      returnValue = responseEntity.getBody();
      if (returnValue == null) {
        mavContainer.setRequestHandled(true);
        outputMessage.flush();
        return;
      }
    }
    ServletRequest request = webRequest.getNativeRequest(ServletRequest.class);
    Assert.state(request != null, "No ServletRequest");
    ShallowEtagHeaderFilter.disableContentCaching(request); // 禁用内容缓存
    Assert.isInstanceOf(StreamingResponseBody.class, returnValue, "StreamingResponseBody expected");
    StreamingResponseBody streamingBody = (StreamingResponseBody) returnValue;
    // 最终也是开启了一个Callable 任务,最后交给WebAsyncUtils去执行的~~~~
    Callable<Void> callable = new StreamingResponseBodyTask(outputMessage.getBody(), streamingBody);
    // WebAsyncUtils.getAsyncManager得到的是一个`WebAsyncManager`对象
    // startCallableProcessing会把callable任务都包装成一个`WebAsyncTask`,最终交给`AsyncTaskExecutor`执行
    // 至于异步的详细执行原理,请参考上面的相关博文,此处只点一下~~~~
    WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
  }
  // 这个任务很简单,实现了Callable的call方法,它就是相当于启一个线程,把本次body里面的内容写进response输出流里面~~~
  // 但是此时输出流并不会关闭~~~~
  private static class StreamingResponseBodyTask implements Callable<Void> {
    private final OutputStream outputStream;
    private final StreamingResponseBody streamingBody;
    public StreamingResponseBodyTask(OutputStream outputStream, StreamingResponseBody streamingBody) {
      this.outputStream = outputStream;
      this.streamingBody = streamingBody;
    }
    @Override
    public Void call() throws Exception {
      this.streamingBody.writeTo(this.outputStream);
      return null;
    }
  }
}


可以看出它的原理是自己构建出一个内部的异步线程,交给reponse的异步上下文去处理。


由上面代码课件,它不仅仅支持json内容,也是支持一直返回页面渲染的内容的。(只是大多数情况下我们把它和@ResponseBody联合使用)


DeferredResultMethodReturnValueHandler

这个也许是我们最为常用的一种异步处理方式。它不仅仅处理返回值类型为DeferredResult,也会处理返回值类型为ListenableFuture和CompletionStage(Java8新增的接口)类型的


public class DeferredResultMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
  // 它支持处理丰富的数据类型
  @Override
  public boolean supportsReturnType(MethodParameter returnType) {
    Class<?> type = returnType.getParameterType();
    return (DeferredResult.class.isAssignableFrom(type) ||
        ListenableFuture.class.isAssignableFrom(type) ||
        CompletionStage.class.isAssignableFrom(type));
  }
  @Override
  public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    // 一样的  只有返回null了才代表此请求处理完成了
    if (returnValue == null) {
      mavContainer.setRequestHandled(true);
      return;
    }
    DeferredResult<?> result;
    // 此处是适配器模式的使用,最终都适配成了一个DeferredResult(使用的内部类实现的~~~)
    if (returnValue instanceof DeferredResult) {
      result = (DeferredResult<?>) returnValue;
    } else if (returnValue instanceof ListenableFuture) {
      result = adaptListenableFuture((ListenableFuture<?>) returnValue);
    } else if (returnValue instanceof CompletionStage) {
      result = adaptCompletionStage((CompletionStage<?>) returnValue);
    } else {
      // Should not happen...
      throw new IllegalStateException("Unexpected return value type: " + returnValue);
    }
    // 此处调用的异步方法是:startDeferredResultProcessing
    WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(result, mavContainer);
  }
  // 下为两匿名内部实现类做的兼容适配、兼容处理~~~~~非常的简单~~~~
  private DeferredResult<Object> adaptListenableFuture(ListenableFuture<?> future) {
    DeferredResult<Object> result = new DeferredResult<>();
    future.addCallback(new ListenableFutureCallback<Object>() {
      @Override
      public void onSuccess(@Nullable Object value) {
        result.setResult(value);
      }
      @Override
      public void onFailure(Throwable ex) {
        result.setErrorResult(ex);
      }
    });
    return result;
  }
  private DeferredResult<Object> adaptCompletionStage(CompletionStage<?> future) {
    DeferredResult<Object> result = new DeferredResult<>();
    future.handle((BiFunction<Object, Throwable, Object>) (value, ex) -> {
      if (ex != null) {
        result.setErrorResult(ex);
      }
      else {
        result.setResult(value);
      }
      return null;
    });
    return result;
  }
}


CallableMethodReturnValueHandler


因为已经解释了StreamingResponseBodyReturnValueHandler,它最终也是转换为一个Callable去处理了的。因此此处返回值直接是callable,简直就不要太简单了~~~


ResponseBodyEmitterReturnValueHandler


XXXEmitter它相当于加强版的DeferredResult,它可以返回多个值给客户端。其实它的底层原理还是DeferredResult,此处不再做过多的介绍~~~~


AsyncTaskMethodReturnValueHandler


顾名思义,它是专门处理返回值类型为WebAsyncTask的异步请求形式。

// @since 3.2  因为WebAsyncTask这个时候才出来~~~
public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
  @Nullable
  private final BeanFactory beanFactory;
  public AsyncTaskMethodReturnValueHandler(@Nullable BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
  }
  @Override
  public boolean supportsReturnType(MethodParameter returnType) {
    return WebAsyncTask.class.isAssignableFrom(returnType.getParameterType());
  }
  @Override
  public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    if (returnValue == null) {
      mavContainer.setRequestHandled(true);
      return;
    }
    WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue;
    if (this.beanFactory != null) {
      webAsyncTask.setBeanFactory(this.beanFactory);
    }
    // 我们发现它使用的也是startCallableProcessing...
  WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);
  }
}


代码逻辑非常简单


HandlerMethodReturnValueHandlerComposite:处理器合成


这是个厉害角色。其实它就是提供的所有的HandlerMethodReturnValueHandler集合,它定义了一个链表用于存储所有实现的HandlerMethodReturnValueHandler。


它用在RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver里,此处以RequestMappingHandlerAdapter为例:


public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
    implements BeanFactoryAware, InitializingBean {
  // 这里保存在用户自定义的一些处理器,大部分情况下无需自定义~~~
  @Nullable
  private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
  // 保存着所有的处理器~~~~上面custom自定义的最终也会放进来,放在尾部
  // 从它的命名似乎可议看出,它就是汇总~~~
  @Nullable
  private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
  // 可以看到即使你调用了set方法,最终也是会给你生成一个HandlerMethodReturnValueHandlerComposite
  public void setReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
    if (returnValueHandlers == null) {
      this.returnValueHandlers = null;
    } else {
      this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
      this.returnValueHandlers.addHandlers(returnValueHandlers);
    }
  }
  @Nullable
  public List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
    return (this.returnValueHandlers != null ? this.returnValueHandlers.getHandlers() : null);
  }
  // 它的初始化发生在这:
  @Override
  public void afterPropertiesSet() {
    ...
    // 相当于你自己没有set,那就交给Spring自己去处理吧~~~~
    if (this.returnValueHandlers == null) {
      // 这个getDefaultReturnValueHandlers()会装载15个左右的返回值处理器,可以说覆盖我们日常开发的所有
      // 若你自己自定义了custom的,放进了customReturnValueHandlers里,最终也会被加进来放进去~~~~ 放在末尾~~~~
      List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
      this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
    }
  }
}


Composite:混合成的,由此可见它就是和汇总的作用。

那么接下来,就看看它本尊自身,提供了哪些能力?其实它的代码量不大:


// 首先发现,它也实现了接口HandlerMethodReturnValueHandler 
// 它会缓存以前解析的返回类型以加快查找速度
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
  private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
  // 返回的是一个只读视图
  public List<HandlerMethodReturnValueHandler> getHandlers() {
    return Collections.unmodifiableList(this.returnValueHandlers);
  }
  public HandlerMethodReturnValueHandlerComposite addHandler(HandlerMethodReturnValueHandler handler) {
    this.returnValueHandlers.add(handler);
    return this;
  }
  public HandlerMethodReturnValueHandlerComposite addHandlers( @Nullable List<? extends HandlerMethodReturnValueHandler> handlers) {
    if (handlers != null) {
      this.returnValueHandlers.addAll(handlers);
    }
    return this;
  }
  // 由这两个可议看出,但凡有一个Handler支持处理这个返回值,就是支持的~~~
  @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;
  }
  // 这里就是处理返回值的核心内容~~~~~
  @Override
  public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    // selectHandler选择收个匹配的Handler来处理这个返回值~~~~ 若一个都木有找到  抛出异常吧~~~~
    // 所有很重要的一个方法是它:selectHandler()  它来匹配,以及确定优先级
    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    if (handler == null) {
      throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    }
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
  }
  // 根据返回值,以及返回类型  来找到一个最为合适的HandlerMethodReturnValueHandler
  @Nullable
  private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
    // 这个和我们上面的就对应上了  第一步去判断这个返回值是不是一个异步的value(AsyncHandlerMethodReturnValueHandler实现类只能我们自己来写~)
    boolean isAsyncValue = isAsyncReturnValue(value, returnType);
    for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
      // 如果判断发现这个值是异步的value,那它显然就只能交给你自己定义的异步处理器处理了,别的处理器肯定就靠边站~~~~~
      if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
        continue;
      }
      if (handler.supportsReturnType(returnType)) {
        return handler;
      }
    }
    return null;
  }
  private boolean isAsyncReturnValue(@Nullable Object value, MethodParameter returnType) {
    for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
      if (handler instanceof AsyncHandlerMethodReturnValueHandler && ((AsyncHandlerMethodReturnValueHandler) handler).isAsyncReturnValue(value, returnType)) {
        return true;
      }
    }
    return false;
  }
}



我们可以看到,它内的逻辑其实非常的简单。重点在于我们需要关心下调用栈:


请求的入口处在这:doDispatcher里会找到一个HandlerAdapter会调用@handle方法来真正执行Spring MVC的Handler。扔给ServletInvocableHandlerMethod#invokeAndHandle去执行处理器,从而拿到方法返回值:returnValue。

最终交给HandlerMethodReturnValueHandlerComposite#handleReturnValue它去处理~~~上面看了源码处理过程,这就简单了,其实最终做事的是我们的具体的找到唯一的一个HandlerMethodReturnValueHandler~


Spring MVC默认配置返回值处理器们

不管开启@EnableWebMvc还是未开启,都是15个


备注:如果是Spring5一下的版本,若未开启@EnableWebMvc,处理的类是过时的AnnotationMethodHandlerAdapter,而它里面还并没有HandlerMethodReturnValueHandler这个接口,所以此处就不介绍了,知道就行。注意版本必须是Spring5以内的,因为Spring5以后那两个过时的类就直接都干掉了~~~


image.png

请注意,上面原理已经讲过,这里面处理器的先后顺序还是比较重要的~~~从下面源码处也能看出,Spring MVC大致上做了分类



  private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
    List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
    // Single-purpose return value types
    // 目的单纯的返回值处理器(这个一般都和视图解析器有关,当然还有异步~)
    handlers.add(new ModelAndViewMethodReturnValueHandler());
    handlers.add(new ModelMethodProcessor());
    handlers.add(new ViewMethodReturnValueHandler());
    handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
        this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
    handlers.add(new StreamingResponseBodyReturnValueHandler());
    handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
        this.contentNegotiationManager, this.requestResponseBodyAdvice));
    handlers.add(new HttpHeadersReturnValueHandler());
    handlers.add(new CallableMethodReturnValueHandler());
    handlers.add(new DeferredResultMethodReturnValueHandler());
    handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
    // Annotation-based return value types
    // 基于注解的返回值处理器:@ModelAttribute和@ResponseBody
    handlers.add(new ModelAttributeMethodProcessor(false));
    handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
        this.contentNegotiationManager, this.requestResponseBodyAdvice));
    // Multi-purpose return value types
    // 多值返回处理器  这两个其实相对稍微复杂点,功能强大点
    handlers.add(new ViewNameMethodReturnValueHandler());
    handlers.add(new MapMethodProcessor());
    // Custom return value types
    // 用户自定义的处理器们~~~~顺序是非常靠后的哟~
    if (getCustomReturnValueHandlers() != null) {
      handlers.addAll(getCustomReturnValueHandlers());
    }
    // Catch-all:处理所有
    // Spring MVC相当于它定位成自己是能够处理所有的请求的~~~~
    // 特别是ModelAndViewResolverMethodReturnValueHandler,我们上面也有举例了
    if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
      handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
    }
    else {
      handlers.add(new ModelAttributeMethodProcessor(true));
    }
    return handlers;
  }


备注:若遇上多个处理器都能处理器的情况下,是按照添加顺序执行的。比如Jackson和FastJson都能处理,那就根据添加顺序了,最终生效的肯定只有一个


总结


Spring MVC支持各种返回值类型,是因为默认给我们注册了足够锁的返回值处理器。它面向接口编程以及对责任链模式很好的使用,实现了非常高的扩展性和解耦性。


一个成熟的框架,体现在它对很多细节上的处理,这才行程了一个产品,而Spring Framework就是这么样一个很优秀的产品,值得参考、学习

相关文章
|
19天前
|
Java 应用服务中间件 Nacos
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
31 0
|
1月前
|
JSON 前端开发 Java
解决Spring MVC中No converter found for return value of type异常
在Spring MVC开发中遇到`No converter found for return value of type`异常,通常是因缺少消息转换器、返回值类型不支持或转换器优先级配置错误。解决方案包括:1) 添加对应的消息转换器,如`MappingJackson2HttpMessageConverter`;2) 自定义消息转换器并实现`HttpMessageConverter`接口,设置优先级;3) 修改返回值类型为如`ResponseEntity`的合适类型。通过这些方法可确保返回值正确转换为响应内容。
39 1
|
1月前
|
前端开发 Java 数据库连接
Spring系列文章1:Spring入门程序
Spring系列文章1:Spring入门程序
|
3天前
|
前端开发 Java 应用服务中间件
Spring MVC框架概述
Spring MVC 是一个基于Java的轻量级Web框架,采用MVC设计模型实现请求驱动的松耦合应用开发。框架包括DispatcherServlet、HandlerMapping、Handler、HandlerAdapter、ViewResolver核心组件。DispatcherServlet协调这些组件处理HTTP请求和响应,Controller处理业务逻辑,Model封装数据,View负责渲染。通过注解@Controller、@RequestMapping等简化开发,支持RESTful请求。Spring MVC具有清晰的角色分配、Spring框架集成、多种视图技术支持以及异常处理等优点。
11 1
|
29天前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
23 3
|
29天前
|
存储 前端开发 Java
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
14 1
|
29天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
33 3
|
29天前
|
前端开发 Java 容器
家族传承:Spring MVC中父子容器的搭建与管理指南
家族传承:Spring MVC中父子容器的搭建与管理指南
26 3
|
29天前
|
前端开发 Java API
头头是道:揭示Spring MVC如何获取和处理请求头数据
头头是道:揭示Spring MVC如何获取和处理请求头数据
26 1
|
29天前
|
前端开发 Java API
饼干探秘:深入Spring MVC中获取Cookie数据的技术解析
饼干探秘:深入Spring MVC中获取Cookie数据的技术解析
18 3