Spring Boot:如何使用 WebClient 而不是 RestTemplate 来执行非阻塞和异步调用

2023-11-25

我有一个使用 Springboot Resttemplate 的 springboot 项目。我们已经从 1.5.3 迁移到 springboot 2.0.1,我们正在尝试使 其余部分通过使用 WebClient 异步调用。我们曾经使用 Resttemplate 处理接收到的字符串,如下所示。但 WebClient 仅返回 Mono 或 Flux 中的数据。我怎样才能得到字符串数据。已经尝试过 block() 方法,但它执行异步调用。

@Retryable(maxAttempts = 4, value = java.net.ConnectException.class,
           backoff = @Backoff(delay = 3000, multiplier = 2))
public Mono<String> getResponse(String url) {
    return webClient.get().uri(urlForCurrent).accept(APPLICATION_JSON)
                    .retrieve()
                    .bodyToMono(String.class);
}

使用 RestTemplate 呈现数据流

  1. 控制器接收客户端调用
  2. 提供者获取字符串格式的数据
  3. 提供者处理字符串
  4. 数据提供给控制器

控制器.java

@RequestMapping(value = traffic/, method = RequestMethod.GET,
                produces = MediaType.APPLICATION_JSON_VALUE)
public String getTraffic(@RequestParam("place") String location) throws InterruptedException, ExecutionException {
    String trafficJSON = Provider.getTrafficJSON(location)
    return trafficJSON;
}

提供者.java

public String getTrafficJSON(String location) {
    String url = ----;

    ResponseEntity<String> response = dataFetcher.getResponse(url);

    /// RESPONSEBODY IS READ AS STRING AND IT NEEDS TO BE PROCESSED
    if (null != response {
        return parser.transformJSON(response.getBody(), params);
    }

    return null;
}

数据获取器.java

@Retryable(maxAttempts = 4,
           value = java.net.ConnectException.class,
           backoff = @Backoff(delay = 3000, multiplier = 2))
public ResponseEntity<String> getResponse(String url) {
    /* ----------------------- */
    return getRestTemplate().getForEntity(urlForCurrent, String.class);
}

由于存在很多误解,所以在这里我要澄清一些事情。

Spring官方表示RestTemplate is in maintenence mode所以如果可以的话,使用WebClient如果您想尽可能面向未来。

如中所述RestTemplate API

NOTE:从 5.0 开始,此类处于维护模式,仅接受较小的更改请求和错误。请考虑使用org.springframework.web.reactive.client.WebClient它具有更现代的 API,支持同步、异步和流场景。

非反应性应用

如果您的应用程序是非反应式应用程序(不向调用客户端返回通量或单声道),您需要做的是使用block()如果你需要这个值。你当然可以使用Mono or Flux在您的应用程序内部,但最终您必须调用block()获取需要返回给调用客户端的具体值。

非反应式应用程序使用例如tomcat, undertow作为底层服务器实现,它遵循 servlet 规范,因此它将为每个请求分配 1 个线程,因此您将无法获得响应式应用程序所获得的性能提升。

反应式应用程序

另一方面,如果您有一个反应式应用程序,则在任何情况下都不应该调用block()在您的应用程序中。阻塞正如它所说的那样,它会阻塞一个线程并阻塞该线程的执行,直到它可以继续前进,这在反应式世界中是不好的。

你也不应该打电话subscribe在你的申请中除非您的应用程序是响应的最终消费者。例如,如果您调用 api 来获取数据并将其写入应用程序连接到的数据库中。您的后端应用程序是最终的消费者。如果外部客户端正在调用您的后端(例如反应、角度应用程序、移动客户端等),则外部客户端是最终消费者,并且是订阅者。不是你。

这里的底层默认服务器实现是netty服务器是一个非 servlet、基于事件的服务器,它将not为每个请求分配一个线程,服务器本身与线程无关,任何可用的线程都可以在任何请求期间随时处理任何事情。

The webflux 文档明确指出servlet 3.1+支持的服务器tomcat和jetty都可以与webflux以及非serlet服务器netty和undertow一起使用。

我怎么知道我有什么应用程序?

Spring 声明如果你两者都有spring-web and spring-webflux在类路径上,应用程序将倾向于spring-web并默认启动一个带有底层 tomcat 服务器的非响应式应用程序。

如果需要作为弹簧状态,可以手动覆盖此行为。

两者都添加spring-boot-starter-web and spring-boot-starter-webflux应用程序中的模块会导致 Spring Boot 自动配置 Spring MVC,而不是 WebFlux。选择这种行为是因为许多 Spring 开发人员添加了spring-boot-starter-webflux他们的 Spring MVC 应用程序使用反应式 WebClient。您仍然可以通过将所选应用程序类型设置为来强制执行您的选择SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE).

“Spring WebFlux 框架”

那么如何按照问题提供的代码实现WebClient呢?

@Retryable(maxAttempts = 4,
       value = java.net.ConnectException.class,
       backoff = @Backoff(delay = 3000, multiplier = 2))
public Mono<String> getResponse(String url) {
    return webClient.get()
            .uri(url)
            .exchange()
            .flatMap(response -> response.toEntity(String.class));
}

我想说这是最简单且侵入性最小的实现。您当然需要构建一个合适的网络客户端@Bean并将其自动装配到其类中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot:如何使用 WebClient 而不是 RestTemplate 来执行非阻塞和异步调用 的相关文章

随机推荐

  • 我是否使用正确的方法来监视创建句柄时要执行的任务?

    是否有普遍接受的最佳实践来创建自行取消订阅的事件处理程序 例如 我想到的第一件事是 Foo cs Bar bar new Bar add l req d state EventHandler handler new EventHandler
  • 在 Android 应用程序中从 Java JSch 中的字符串或资源加载私钥

    我正在编写一个应用程序 该应用程序应该使用 JSch 通过 SSH 访问我的私人服务器 由于我已经设置了公钥身份验证 因此我希望此应用程序以相同的方式进行身份验证 我将是唯一使用此应用程序的人 因此我想将我的密钥直接存储在应用程序内 例如硬
  • 如何使用 git-cache-meta?

    我想将目录的权限保留在 git 存储库中 似乎一种简单的方法是使用git cache meta 其用途的示例和最小解释是什么 如果您指的是this实施git cache meta 那么您需要做的就是确保该脚本位于您的 PATH 中 将其放入
  • 当警告趋势出现时,如何将构建标记为不稳定?

    因此 我们将 Jenkins 与 MS Build 结合使用来构建我们的项目 我们还有一个警告插件以及我们项目中的大量警告 我正在努力与这些警告作斗争 我想要采取的步骤之一是 当最后一个构建中的警告数量大于前一个构建时 将构建标记为不稳定
  • PHP 中的整数四舍五入到最接近的 5 的倍数

    搜索将数字四舍五入到最接近的 5 倍数的函数 22 gt 20 23 gt 25 40 gt 40 46 gt 45 48 gt 50 等等 尝试过这个总是返回更高的值 5 ceil n 5 Use round 代替ceil 5 round
  • Laravel:任务调度[并行]

    我有多项任务需要每隔一两个小时完成一次 所有这些都已通过 Laravel 使用以下命令作为 cron 作业进行安排 schedule gt command email notifications1 gt cron 15 schedule g
  • 如何在package.json中使用环境变量

    因为我们不希望项目代码中包含敏感数据 包括 package json 文件 所以在我看来 使用环境变量将是一个合理的选择 示例 package json dependencies accounting 0 4 0 async 1 4 2 m
  • JavaScript 中的 For..In 循环 - 键值对

    我想知道是否有办法做类似 PHP 的事情foreachJavaScript 中的循环 我正在寻找的功能类似于这个 PHP 片段 foreach data as key gt value 我正在看JSfor in循环 但似乎没有办法指定as
  • dyld:未加载库:@rpath/libswiftCore.dylib /未找到图像

    我正在从 xcode 到我的 iOS 设备运行我的应用程序 并且在 iOS 设备上出现此屏幕和黑屏 控制台文本 dyld Library not loaded rpath libswiftCore dylib Referenced from
  • 如何设置(组合)表中的两个主键

    对于一个小型的销售相关应用程序 我们使用逻辑数据模型设计数据库 上台转换成实体模型 在SQL Server Management Studio Express中创建表时 根据我们的逻辑数据模型 我们需要组合两个属性来形成唯一的id 是否可以
  • 什么是协程?

    什么是协程 它们与并发有何关系 协程和并发在很大程度上是正交的 协程是一种通用控制结构 流量控制在两个不同的例程之间协作传递而不返回 Python 中的 yield 语句就是一个很好的例子 它创建一个协程 当遇到 yield 时 函数的当前
  • 我如何知道我的 ansible 使用的是哪个版本的 Jinja2?

    我尝试使用pip list and pip freeze没有成功 这可能是显而易见的事情 但到目前为止我还无法找到它 将此文件拖放到 action plugins jin ver py from ansible plugins action
  • python 在哪里查找 Windows 上由 ctypes.cdll. 打开的 dll?

    恐怕我在互联网上找不到这个问题的简单答案 所以也许将来会因为这个问题而找到一个简单的答案 我正在使用 pywiiuse 它是 Windows 上 C wiiuse 库的 python 包装器 我已经获得了几个简单的 C 示例 只需将 dll
  • 是否可以使字母间距相对于字体大小并正确继承?

    我的问题与此基本相同 但将 line height 替换为 letter spacing 当继承相对行高时 它与元素的字体大小无关 为什么 我如何使其相对 我的用例是这样的 body font size 18px letter spacin
  • SQLite 与 EF Code First

    在我成功地将 SQLite 与 NHibernate 结合使用之后 我很高兴使用它来通过 Entity Framework Code First 进行测试 如果您有一些示例连接字符串并设置演示 那就太好了 可以为我忙碌的一天节省一些时间 多
  • 检索 R 中特定单元格的行名和列名

    因此 如果我有一个如下所示的数据框 A B C rowname1 4 5 4 3 2 rowname2 3 23 9 如何让 R 给出包含特定数字的行 列的名称 即如果我给出值 3 它会返回 rowname2 A 假设没有重复项 您可以使用
  • C# 委托未绑定到实例?

    有没有一种方法可以存储委托而不将其绑定到对象 就像使用 MethodInfo 一样 现在我正在存储一个 MethodInfo 这样我就可以给它一个对象来调用该方法 但我更愿意让它成为一名代表 就像有一个属性告诉 net 第一个参数是 thi
  • 使用 VBA 连接到 MS Access 中的 Web 服务

    是否可以通过 VBA 连接到 Web 服务 例如发送 HTTP 请求 in微软访问 例如 用户单击表单上的按钮 然后将 HTTP 请求发送到 Web 服务 该服务以OK 以前有人这样做过吗 注意 VBA 而不是 VB NET 这是我在 Ac
  • 将多维 PHP 数组转换为 javascript 数组

    我正在尝试使用 JSON 编码器将 PHP 多维数组转换为 javascript 数组 当我执行 var dump 时 我的 php 数组如下所示 array size 2 Key gt string a length 1 Value gt
  • Spring Boot:如何使用 WebClient 而不是 RestTemplate 来执行非阻塞和异步调用

    我有一个使用 Springboot Resttemplate 的 springboot 项目 我们已经从 1 5 3 迁移到 springboot 2 0 1 我们正在尝试使 其余部分通过使用 WebClient 异步调用 我们曾经使用 R