RestTemplate组件:ClientHttpRequestFactory、ClientHttpRequestInterceptor、ResponseExtractor【享学Spring MVC】(下)

简介: RestTemplate组件:ClientHttpRequestFactory、ClientHttpRequestInterceptor、ResponseExtractor【享学Spring MVC】(下)

ResponseExtractor


响应提取器:从Response中提取数据。RestTemplate请求完成后,都是通过它来从ClientHttpResponse提取出指定内容(比如请求头、请求Body体等)~


image.png


它的直接实现似乎只有HttpMessageConverterExtractor,当然它也是最为重要的一个实现,和HttpMessageConverter相关。

在解释它之前,先看看这个:MessageBodyClientHttpResponseWrapper,它的特点:它不仅可以通过实际读取输入流来检查响应是否有消息体,还可以检查其长度是否为0(即空)


// @since 4.1.5  它是一个访问权限是default的类,是对其它ClientHttpResponse的一个包装
class MessageBodyClientHttpResponseWrapper implements ClientHttpResponse {
  private final ClientHttpResponse response;
  // java.io.PushbackInputStream
  @Nullable
  private PushbackInputStream pushbackInputStream;
  // 判断相应里是否有body体
  // 若响应码是1xx 或者是204;或者getHeaders().getContentLength() == 0 那就返回false  否则返回true
  public boolean hasMessageBody() throws IOException {
    HttpStatus status = HttpStatus.resolve(getRawStatusCode());
    if (status != null && (status.is1xxInformational() || status == HttpStatus.NO_CONTENT || status == HttpStatus.NOT_MODIFIED)) {
      return false;
    }
    if (getHeaders().getContentLength() == 0) {
      return false;
    }
    return true;
  }
  // 上面是完全格局状态码(ContentLength)来判断是否有body体的~~~这里会根据流来判断
  // 如果response.getBody() == null,返回true
  // 若流里有内容,最终就用new PushbackInputStream(body)包装起来~~~
  public boolean hasEmptyMessageBody() throws IOException {
    ...
  }
  ...  // 其余接口方法都委托~
  @Override
  public InputStream getBody() throws IOException {
    return (this.pushbackInputStream != null ? this.pushbackInputStream : this.response.getBody());
  }
}


它的作用就是包装后,提供两个方法hasMessageBody、hasEmptyMessageBody方便了对body体内容进行判断


// @since 3.0 泛型T:the data type
public class HttpMessageConverterExtractor<T> implements ResponseExtractor<T> {
  // java.lang.reflect.Type
  private final Type responseType;
  // 这个泛型也是T,表示数据的Class嘛~
  // 该calss有可能就是上面的responseType
  @Nullable
  private final Class<T> responseClass;
  // 重要:用于消息解析的转换器
  private final List<HttpMessageConverter<?>> messageConverters;
  ... // 省略构造函数
  // 从ClientHttpResponse 里提取值
  @Override
  @SuppressWarnings({"unchecked", "rawtypes", "resource"})
  public T extractData(ClientHttpResponse response) throws IOException {
    MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
    // 若没有消息体(状态码不对 或者 消息体为空都被认为是木有)
    if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {
      return null;
    }
    // content-type若响应头header里没有指定,那默认是它MediaType.APPLICATION_OCTET_STREAM
    MediaType contentType = getContentType(responseWrapper);
    // 遍历所有的messageConverters,根据contentType 来选则一个消息转换器
    // 最终return messageConverter.read((Class) this.responseClass, responseWrapper)
    ...
  }
}


它的处理逻辑理解起来非常简单:利用contentType找到一个消息转换器,最终HttpMessageConverter.read()把消息读出来转换成Java对象。

它还有两个内部类的实现如下(都是RestTemplate的私有内部类):



RestTemplate:
  // 提取为`ResponseEntity`  最终委托给HttpMessageConverterExtractor完成的
  private class ResponseEntityResponseExtractor<T> implements ResponseExtractor<ResponseEntity<T>> {
    @Nullable
    private final HttpMessageConverterExtractor<T> delegate;
    public ResponseEntityResponseExtractor(@Nullable Type responseType) {
      // 显然:只有请求的返回值不为null 才有意义~
      if (responseType != null && Void.class != responseType) {
        this.delegate = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
      } else {
        this.delegate = null;
      }
    }
    // 数据提取。都是交给`delegate.extractData(response)`做了,然后new一个ResponseEntity出来包装进去
    // 若木有返回值(delegate=null),那就是一个`ResponseEntity`实例,body为null
    @Override
    public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
      if (this.delegate != null) {
        T body = this.delegate.extractData(response);
        return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(body);
      }
      else {
        return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).build();
      }
    }
  }
  // 提取请求头
  private static class HeadersExtractor implements ResponseExtractor<HttpHeaders> {
    @Override
    public HttpHeaders extractData(ClientHttpResponse response) {
      return response.getHeaders();
    }
  }


UriTemplateHandler

这个组件它用于定义用变量扩展uri模板的方法


// @since 4.2 出现较晚  
// @see RestTemplate#setUriTemplateHandler(UriTemplateHandler)
public interface UriTemplateHandler {
  URI expand(String uriTemplate, Map<String, ?> uriVariables);
  URI expand(String uriTemplate, Object... uriVariables);
}


关于URI的处理,最终都是委托给UriComponentsBuilder来完成。若对这块还存在一定疑问的,强烈强烈强烈 参考这里


推荐阅读


RestTemplate的使用和原理你都烂熟于胸了吗?【享学Spring MVC】


总结


本文介绍的组件是去理解RestTemplate必备的组件们,属于开山篇。因为RestTemplate使用频繁,并且经常需要调优,因此我寄希望大家也能对它做较为深入的了解,这也是我写本系列的目的,共勉。

相关文章
|
1月前
|
SQL JavaScript Java
springboot+springm vc+mybatis实现增删改查案例!
springboot+springm vc+mybatis实现增删改查案例!
26 0
|
13天前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
23 3
|
13天前
|
存储 前端开发 Java
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
14 1
|
13天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
29 3
|
22天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
28天前
|
敏捷开发 监控 前端开发
Spring+SpringMVC+Mybatis的分布式敏捷开发系统架构
Spring+SpringMVC+Mybatis的分布式敏捷开发系统架构
66 0
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
42 0
|
8月前
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
116 0
|
9月前
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
67 0
|
9月前
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(一)
[回馈]ASP.NET Core MVC开发实战之商城系统(一)
113 0