您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

Spring6提供的四种远程接口调用神器!你知道那种?

时间:2023-12-11 13:03:22  来源:  作者:Spring全家桶实战案例源码

1. 介绍

Spring 6是一个非常强大的框架,它提供了许多工具和接口来简化远程接口调用。其中,WebClient、RestTemplate、HTTP Interface和RestClient是四种方式。

WebClient是Spring 5中新引入的一个接口基于响应式,它提供了一种更简单、更灵活的方式来调用远程接口。与RestTemplate相比,WebClient更加现代化,具有更好的性能和更低的内存占用。

RestTemplate是Spring 3中引入的一个接口,它提供了一种更加简单、更加直观的方式来调用远程接口。虽然WebClient是更现代化的选择,但RestTemplate仍然是一种常用的远程接口调用方式。

HTTP Interface将 HTTP 服务定义为一个 JAVA 接口,其中包含用于 HTTP 交换的注解方法。然后,你可以生成一个实现该接口并执行交换的代理。这有助于简化 HTTP 远程访问,因为远程访问通常需要使用一个门面来封装使用底层 HTTP 客户端的细节。

RestClient是一个同步 HTTP 客户端,提供现代、流畅的 API。它为 HTTP 库提供了一个抽象,可以方便地从 Java 对象转换为 HTTP 请求,并从 HTTP 响应创建对象。

下面分别介绍4个REST接口调用的详细使用。

2. 远程接口调用

RestTemplate

RestTemplate 提供了比 HTTP 客户端库更高级别的 API。它使调用 REST 端点变得简单易行。它公开了以下几组重载方法:

方法

描述

getForObject

通过GET检索数据。

getForEntity

使用 GET 获取响应实体(即状态、标头和正文)。

headForHeaders

使用 HEAD 读取资源的所有标头。

postForLocation

使用 POST 创建新资源,并从响应中返回位置标头。

postForObject

使用 POST 创建一个新资源,并从响应中返回描述。

postForEntity

使用 POST 创建一个新资源,并从响应中返回描述。

put

使用 PUT 创建或更新资源。

patchForObject

使用 PATCH 更新资源,并返回响应中的描述。请注意,JDK HttpURLConnection 不支持 PATCH,但 Apache HttpComponents 和其他组件支持。

delete

使用 DELETE 删除指定 URI 上的资源。

optionsForAllow

通过 ALLOW 读取资源允许使用的 HTTP 方法。

exchange

前述方法的更通用(更少意见)版本,可在需要时提供额外的灵活性。它接受一个 RequestEntity(包括作为输入的 HTTP 方法、URL、标题和正文),并返回一个 ResponseEntity。

这些方法允许使用参数化类型引用(ParameterizedTypeReference)而不是类(Class)来指定具有泛型的响应类型。

execute

执行请求的最通用方式,可通过回调接口完全控制请求准备和响应提取。

  • 初始化

默认构造函数使用 java.NET.HttpURLConnection 来执行请求。你可以通过 ClientHttpRequestFactory 的实现切换到不同的 HTTP 库。目前,该程序还内置了对 Apache HttpComponents 和 OkHttp 的支持。示例:

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());

每个 ClientHttpRequestFactory 都会公开底层 HTTP 客户端库的特定配置选项,例如,凭证、连接池和其他细节。

  • URIs

许多 RestTemplate 方法都接受 URI 模板和 URI 模板变量,可以是字符串变量参数,也可以是 Map<String,String>。

String result = restTemplate.getForObject(
    "http://pack.com/users/{userId}", String.class, 666) ;

Map<String, ?>方式:

Map<String, Object> params = Collections.singletonMap("userId", 666);


String result = restTemplate.getForObject(
    "http://pack.com/users/{userId}", String.class, params) ;
  • Headers

可以使用 exchange() 方法指定请求头,如下例所示:

String uriTemplate = "http://pack.com/users/{userId}";
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42);


RequestEntity<Void> requestEntity = RequestEntity.get(uri)
    .header("x-api-token", "aabbcc")
    .build() ;
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
String responseHeader = response.getHeaders().getFirst("x-version");
String body = response.getBody() ;
  • body

如果你当前CLASSPATH存在MAppingJackson2HttpMessageConverter,那么你可以直接将请求结果映射为你所需要的结果对象,如下示例所示,将目标接口返回值直接转换为User对象。

User user = restTemplate.getForObject("http://pack.com/users/{userId}", User.class, 666);

默认情况下,RestTemplate 会注册所有内置的消息转换器,这决定于你当前类路径是否有相应的转换库。你也可以显式设置要使用的消息转换器。默认构造函数如下:

public RestTemplate() {
  this.messageConverters.add(new ByteArrayHttpMessageConverter());
  this.messageConverters.add(new StringHttpMessageConverter());
  this.messageConverters.add(new ResourceHttpMessageConverter(false));
  // ...其它转换器
  if (jackson2Present) {
    this.messageConverters.add(new MappingJackson2HttpMessageConverter());
  }
  else if (gsonPresent) {
    this.messageConverters.add(new GsonHttpMessageConverter());
  }
  else if (jsonbPresent) {
    this.messageConverters.add(new JsonbHttpMessageConverter());
  }
  // ...其它转换器
  this.uriTemplateHandler = initUriTemplateHandler();
}

注意:RestTemplate 目前处于维护模式,只接受小改动和错误请求。请考虑改用 WebClient。

WebClient

WebClient 是执行 HTTP 请求的非阻塞、反应式客户端。它在 5.0 中引入,提供了 RestTemplate 的替代方案,支持同步、异步和流场景。

WebClient 支持以下功能:

  1. 非阻塞 I/O。
  2. 反应流反向压力
  3. 用更少的硬件资源实现高并发。
  4. 利用 Java 8 lambdas 的函数式流畅应用程序接口。
  5. 同步和异步交互。
  6. 服务器上的数据流或服务器下的数据流。

示例:

Mono<Person> result = client.get()
  .uri("/users/{userId}", id).accept(MediaType.APPLICATION_JSON)
  .retrieve()
  .bodyToMono(User.class);

HTTP Interface

Spring Framework 可让你将 HTTP 服务定义为一个 Java 接口,其中包含用于 HTTP 交换的注解方法。然后,你可以生成一个实现该接口并执行交换的代理。这有助于简化 HTTP 远程访问,因为远程访问通常需要使用一个门面来封装使用底层 HTTP 客户端的细节。

首先,声明一个带有 @HttpExchange 方法的接口:

@HttpExchange(url = "/demos")
public interface DemoInterface {


  @PostExchange("/format3/{id}")
  Users queryUser(@PathVariable Long id);


}

创建一个代理,执行所声明的 HTTP exchanges:

@Service
public class DemoService {


  private final DemoInterface demoInterface ;


  public DemoService() {
    // 基于响应式调用;你当前的环境需要引入webflux
    WebClient client = WebClient.builder().baseUrl("http://localhost:8088/").build() ;
    HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build() ;
    this.demoInterface = factory.createClient(DemoInterface.class) ;
  }


  public Users queryUser(Long id) {
    return this.demoInterface.queryUser(id) ;
  }


}

测试接口

@Resource
private DemoService demoService ;




@GetMapping("/{id}")
public Users getUser(@PathVariable("id") Long id) {
  return this.demoService.queryUser(id) ;
}

执行结果

Spring6提供的四种远程接口调用神器!你知道那种?图片

支持的方法参数

方法参数

说明

URI

动态设置请求的 URL,覆盖注解的 url 属性。

HttpMethod

动态设置请求的 HTTP 方法,覆盖注解的方法属性

@RequestHeader

添加一个或多个请求标头。参数可以是包含多个标头的 Map<String, ?> 或 MultiValueMap<String, ?>、值集合<?> 或单个值。

@PathVariable

添加一个变量,用于扩展请求 URL 中的占位符。参数可以是包含多个变量的 Map<String, ?> 或单个值。

@RequestBody

提供请求的正文,既可以是要序列化的对象,也可以是 Reactive Streams Publisher(如 Mono、Flux 或通过配置的 ReactiveAdapterRegistry 支持的任何其他异步类型)。

@RequestParam

添加一个或多个请求参数。参数可以是包含多个参数的 Map<String, ?> 或 MultiValueMap<String, ?>、数值集合<?> 或单个数值。

当 "content-type"设置为 "application/x-www-form-urlencoded "时,请求参数将在请求正文中编码。否则,它们将作为 URL 查询参数添加。

@RequestPart

添加一个请求部分,它可以是字符串(表单字段)、资源(文件部分)、对象(要编码的实体,如 JSON)、HttpEntity(部分内容和标头)、Spring 部分或上述任何部分的 Reactive Streams 发布器。

@CookieValue

添加一个或多个 cookie。参数可以是包含多个 cookie 的 Map<String, ?> 或 MultiValueMap<String, ?>、值集合<?> 或单个值。

支持的返回值

返回值

说明

voidMono<Void>

执行给定的请求,并发布响应内容(如果有)。

HttpHeaders
Mono<HttpHeaders>

执行给定的请求,释放响应内容(如果有),并返回响应标头。

<T>Mono<T>

执行给定的请求,并根据声明的返回类型对响应内容进行解码。

<T>Flux<T>

执行给定的请求,并将响应内容解码为已声明元素类型的数据流。

ResponseEntity<Void>
Mono<ResponseEntity<Void>>

执行给定的请求,释放响应内容(如果有),并返回一个包含状态和标头的 ResponseEntity。

ResponseEntity<T>,
Mono<ResponseEntity<T>>

执行给定的请求,按照声明的返回类型解码响应内容,并返回一个包含状态、标头和解码后正文的 ResponseEntity。

Mono<ResponseEntity<Flux<T>>

执行给定的请求,将响应内容解码为已声明元素类型的数据流,并返回一个包含状态、标头和解码后的响应正文数据流的 ResponseEntity。

异常处理

默认情况下,WebClient为4xx和5xx HTTP状态代码引发WebClientResponseException。要自定义此项,可以注册响应状态处理程序,该处理程序应用于通过客户端执行的所有响应:

WebClient client = WebClient.builder()
    // 状态码为4xx或5xx
    .defaultStatusHandler(HttpStatusCode::isError, resp -> Mono.just(new RuntimeException(resp.statusCode().toString() + "请求错误")))
    .baseUrl("http://localhost:8088/").build() ;
HttpServiceProxyFactory factory = HttpServiceProxyFactory
    .builder(WebClientAdapter.forClient(client)).build() ;

RestClient

该接口是在Spring6.1.1版本中才有的,是一个同步 HTTP 客户端,提供现代、流畅的 API。

创建RestClientRestClient 是通过静态创建方法之一创建的。你还可以使用 builder 获取带有更多选项的生成器,例如指定要使用的 HTTP 库和要使用的消息转换器,设置默认 URI、默认路径变量、默认请求头,或注册拦截器和初始化器。

创建(或构建)后,RestClient 可由多个线程安全使用。

// 默认通过静态方法创建
RestClient restClient = RestClient.create();
// 自定义方式
RestClient restClient = RestClient.builder()
  .requestFactory(new HttpComponentsClientHttpRequestFactory())
  // 自定义消息转换器
  // .messageConverters(converters -> converters.add(new PackCustomMessageConverter()))
  .baseUrl("http://localhost:8088")
  .defaultUriVariables(Map.of("id", "888"))
  .defaultHeader("x-api-token", "aabbcc")
  .requestInterceptor(new ClientHttpRequestInterceptor() {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
        throws IOException {
      System.out.println("我是拦截器") ;
      return execution.execute(request, body) ;
    }
  })
  .requestInitializer(new ClientHttpRequestInitializer() {
    @Override
    public void initialize(ClientHttpRequest request) {
      System.out.println("我是初始化器") ;
      request.getHeaders().add("x-version", "1.0.0") ;
    }
  })
  .build() ;

调用及处理返回值

Users users = customClient.get()
  .uri("/demos/users/{id}")
  .retrieve()
  .body(Users.class) ;

post+body请求方式

Users user = new Users();
ResponseEntity<Void> response = restClient.post() 
  .uri("/demos/users") 
  .contentType(APPLICATION_JSON) 
  .body(user) 
  .retrieve()
  .toBodilessEntity() ;

错误处理默认情况下,当返回状态代码为 4xx 或 5xx 的响应时,RestClient 会抛出 RestClientException 的子类。可以使用 onStatus.RestClientException 命令重写该行为。

Users users = customClient.get()
  .uri("/demos/users/{id}")
  .retrieve()
  // 处理返回状态码为:4xx和5xx
  .onStatus(HttpStatusCode::isError, (request, response) -> {
    throw new RuntimeException(response.getStatusCode().toString() + "请求错误") ;
  })
  .body(Users.class) ;

总结:实现远程接口调用方面的强大功能。无论是使用WebClient、RestTemplate、HTTP Interface还是直接使用RestClient,Spring都提供了丰富的工具和接口来简化开发者的操作。这些工具和接口不仅具有高性能、低内存占用的优点,而且提供了良好的可扩展性和灵活性,使得开发者可以根据实际需求进行定制化开发。



Tags:Spring   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Spring Security:保障应用安全的利器
SpringSecurity作为一个功能强大的安全框架,为Java应用程序提供了全面的安全保障,包括认证、授权、防护和集成等方面。本文将介绍SpringSecurity在这些方面的特性和优势,以及它...【详细内容】
2024-02-27  Search: Spring  点击:(52)  评论:(0)  加入收藏
Spring Security权限控制框架使用指南
在常用的后台管理系统中,通常都会有访问权限控制的需求,用于限制不同人员对于接口的访问能力,如果用户不具备指定的权限,则不能访问某些接口。本文将用 waynboot-mall 项目举例...【详细内容】
2024-02-19  Search: Spring  点击:(39)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  Search: Spring  点击:(8)  评论:(0)  加入收藏
Spring实现Kafka重试Topic,真的太香了
概述Kafka的强大功能之一是每个分区都有一个Consumer的偏移值。该偏移值是消费者将读取的下一条消息的值。可以自动或手动增加该值。如果我们由于错误而无法处理消息并想重...【详细内容】
2024-01-26  Search: Spring  点击:(84)  评论:(0)  加入收藏
SpringBoot如何实现缓存预热?
缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。那么问题来了,在 Spring Boot 项目启动之后,在什么时候?在哪里可以将数据加载到缓存系...【详细内容】
2024-01-19  Search: Spring  点击:(86)  评论:(0)  加入收藏
Spring Boot2.0深度实践 核心原理拆解+源码分析
Spring Boot2.0深度实践:核心原理拆解与源码分析一、引言Spring Boot是一个基于Java的轻量级框架,它简化了Spring应用程序的创建过程,使得开发者能够快速搭建一个可运行的应用...【详细内容】
2024-01-15  Search: Spring  点击:(93)  评论:(0)  加入收藏
SpringBoot3+Vue3 开发高并发秒杀抢购系统
开发高并发秒杀抢购系统:使用SpringBoot3+Vue3的实践之旅随着互联网技术的发展,电商行业对秒杀抢购系统的需求越来越高。为了满足这种高并发、高流量的场景,我们决定使用Spring...【详细内容】
2024-01-14  Search: Spring  点击:(90)  评论:(0)  加入收藏
Spring Boot 3.0是什么?
Spring Boot 3.0是一款基于Java的开源框架,用于简化Spring应用程序的构建和开发过程。与之前的版本相比,Spring Boot 3.0在多个方面进行了改进和增强,使其更加易用、高效和灵活...【详细内容】
2024-01-11  Search: Spring  点击:(130)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11  Search: Spring  点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  Search: Spring  点击:(115)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(4)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(11)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(5)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(8)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(114)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条