文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-11-30 04:03

关注

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 客户端库的特定配置选项,例如,凭证、连接池和其他细节。

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

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

Map方式:

Map params = Collections.singletonMap("userId", 666);


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

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

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


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

如果你当前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 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) ;
}

执行结果

图片

支持的方法参数

方法参数

说明

URI

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

HttpMethod

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

@RequestHeader

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

@PathVariable

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

@RequestBody

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

@RequestParam

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

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

@RequestPart

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

@CookieValue

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

支持的返回值

返回值

说明

voidMono

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

HttpHeaders
Mono

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

Mono

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

Flux

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

ResponseEntity
Mono>

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

ResponseEntity,
Mono>

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

Mono>

执行给定的请求,将响应内容解码为已声明元素类型的数据流,并返回一个包含状态、标头和解码后的响应正文数据流的 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 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都提供了丰富的工具和接口来简化开发者的操作。这些工具和接口不仅具有高性能、低内存占用的优点,而且提供了良好的可扩展性和灵活性,使得开发者可以根据实际需求进行定制化开发。

来源:Spring全家桶实战案例源码内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯