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

简介: RestTemplate的使用和原理你都烂熟于胸了吗?【享学Spring MVC】(下)

所有方法大体执行逻辑一致,都是和RequestCallback、responseExtractor等有关,且最终都是委托给了最为底层的execute()方法去执行。


你是否疑问:它提供的put方法返回值都是void,若我put请求就有返回值肿么办呢?那么接下来就介绍更为通用的一个方法:exchange()


RestTemplate:
  @Override
  public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
    // 把请求体适配为HttpEntity
    RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
    // 消息提取器使用ResponseEntityResponseExtractor
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    // 从上两个部分就能看到:exchange方法的入参、出参都是非常通用的~~~
    return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
  }
  // ParameterizedTypeReference参数化类型,用于处理泛型
  // 上面的responseType就是个Class。这里是个参数化类型~~~~~
  @Override
  public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {
    Type type = responseType.getType();
    RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
    return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
  }
  // 这个方法就非常精简了,让调用者自己去构造RequestEntity,里面是包含了请求的URL和方法等信息的
  @Override
  public <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType) throws RestClientException {
    RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return nonNull(doExecute(requestEntity.getUrl(), requestEntity.getMethod(), requestCallback, responseExtractor));
  }


exchange所有方法使用的都是HttpEntity和ResponseEntity代表请求实体和响应实体,足以见到它设计的通用性。


在Spring3.2后提供了ParameterizedTypeReference来处理参数化类型—> 主要是为了处理List等的泛型


可以发现即使是exchange()方法,最终还是委托给execute/doExecute去执行的:

RestTemplate:
  // 3个execute方法。最终调用的都是doExecute方法
  // 它做的一件事:使用UriTemplateHandler把URL的参数填进去~~~
  // 底层使用的是我上文介绍的`UriComponentsBuilder`,还是比较简单的
  @Override
  @Nullable
  public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
    URI expanded = getUriTemplateHandler().expand(url, uriVariables);
    return doExecute(expanded, method, requestCallback, responseExtractor);
  }
doExecute方法:
  @Nullable
  protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
    ClientHttpResponse response = null;
    ClientHttpRequest request = createRequest(url, method);
    // 如果有回调,那就先回调处理一下子请求
    if (requestCallback != null) {
      requestCallback.doWithRequest(request);
    }
    // 真正意义上的发送请求。
    // 请注意:如果这里的request是`InterceptingClientHttpRequest`,那就回执行拦截器的intercept方法哦~~~
    // 至于什么时候是InterceptingClientHttpRequest呢?这个上面有讲的
    response = request.execute();
    // 处理结果(若有错误,那就抛出异常~~~)
    handleResponse(url, method, response);
    // 请求正常。那就使用返回值提取器responseExtractor提取出内容即可了~~~
    return (responseExtractor != null ? responseExtractor.extractData(response) : null);
    ...
    // 关闭响应(ClientHttpResponse继承了Closeable接口)
    finally {
      if (response != null) {
        response.close();
      }
    }
  }


看完doExecute()的模板式的实现步骤,就清楚了RestTemplate从发出一个请求到收到一个响应的完整过程。Spring设计了多个相关组件,提供钩子程序让我们可以干预到流程里面去,最常见的当然就是请求拦截器了,它在Ribbon负载均衡和Hystrix熔断器里面有很好的应用~


AsyncRestTemplate


它是@since 4.0新增的用于解决一些异步Http请求的场景,但它寿命比较短,在Spring5.0就标记为@Deprecated,而被推荐使用WebClient去代替它。


它的实现基础原理是:RestTemplate + SimpleAsyncTaskExecutor任务池的方式去实现的异步请求,返回值均为ListenableFuture。掌握了RestTemplate后,它使用起来是没有什么障碍的


极简使用Demo Show


看过了原理的描述,我有理由相信你已经烂熟于胸并对RestTemplate能够运用自如了。因此关于使用方面,本文只给如下非常简单的一个Demo Show我认为是够了的:

public static void main(String[] args) throws IOException {
    RestTemplate restTemplate = new RestTemplate();
    String pageHtml = restTemplate.getForObject("http://www.baidu.com", String.class);
    System.out.println(pageHtml); // 百度首页的html...
}


解释一点:这里请求得到的是一个html网页,所以HttpMessageConverterExtractor去提取响应时,使用的是StringHttpMessageConverter去处理的,提取代码如下


StringHttpMessageConverter:
  @Override
  protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
    // 从响应头的contentType里提取(若是application/json,那默认也是urf-8)
    // 若没有指定编码,就取值getDefaultCharset。比如本处访问百度,就取值默认值`ISO-8859-1`对body体进行编码的~
    Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
    return StreamUtils.copyToString(inputMessage.getBody(), charset);
  }


小伙伴把此请求案例可以和上面我使用ClientHttpRequestFactory发送请求的案例对比(或者和你自己使用HttpClient步骤对比),感受感受使用RestTemplate是多么的优雅~


推荐阅读


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

为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】


总结


微服务作为主流的今天,RestTemplate可谓是一把利器,每个程序员都应该掌握它。深入理解它对实际应用、调优都有很现实的意义,所以我相信本文能够帮助到你,做到烂熟于胸。

预告一下:下篇文章会原理分析告诉大家为何一个简单的@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?

相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
28天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
66 1
|
2天前
|
安全 Java API
Spring工厂API与原理
Spring工厂API与原理
23 10
|
14天前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
23 3
|
14天前
|
存储 前端开发 Java
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
14 1
|
14天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
29 3
|
23天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
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条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
117 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