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

简介: 【小家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就是这么样一个很优秀的产品,值得参考、学习

相关文章
|
8月前
|
缓存 安全 Java
《深入理解Spring》过滤器(Filter)——Web请求的第一道防线
Servlet过滤器是Java Web核心组件,可在请求进入容器时进行预处理与响应后处理,适用于日志、认证、安全、跨域等全局性功能,具有比Spring拦截器更早的执行时机和更广的覆盖范围。
|
8月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
739 70
|
10月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
1398 0
|
11月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
345 0
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
379 0
|
10月前
|
Kubernetes Docker Python
Docker 与 Kubernetes 容器化部署核心技术及企业级应用实践全方案解析
本文详解Docker与Kubernetes容器化技术,涵盖概念原理、环境搭建、镜像构建、应用部署及监控扩展,助你掌握企业级容器化方案,提升应用开发与运维效率。
1337 108