java - Spring 启动 : How to use WebClient instead of RestTemplate for Performing Non blocking and Asynchronous calls

标签 java spring spring-boot spring-webflux

我有一个使用 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. Controller 接收客户端调用
  2. 提供者获取字符串格式的数据
  3. Provider 处理字符串
  4. 数据交给控制者

Controller .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;
}

DataFetcher.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 处于维护模式 所以如果可以的话,如果你想成为 future 的证明,请使用 WebClient可能。

RestTemplate API 中所述

NOTE: As of 5.0 this class is in maintenance mode, with only minor requests for changes and bugs to be accepted going forward. Please, consider using the org.springframework.web.reactive.client.WebClient which has a more modern API and supports sync, async, and streaming scenarios.

非 react 性应用

如果您的应用程序是非 react 性应用程序(不向调用客户端返回通量或单声道),您必须做的是在需要该值时使用 block()。您当然可以在您的应用程序内部使用 MonoFlux 但最后您必须调用 block() 来获取您想要的具体值需要返回调用客户端。

非响应式应用程序使用例如 tomcatundertow 作为底层服务器实现,它遵循 servlet 规范,因此它将为每个请求分配 1 个线程,因此您不会获得使用响应式(Reactive)应用程序获得的性能提升。

响应式应用

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

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

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

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

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

Spring 声明,如果类路径中同时有 spring-webspring-webflux,应用程序将优先使用 spring-web 和默认启动一个带有底层 tomcat 服务器的非 react 性应用程序。

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

Adding both spring-boot-starter-web and spring-boot-starter-webflux modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux. This behavior has been chosen because many Spring developers add spring-boot-starter-webflux to their Spring MVC application to use the reactive WebClient. You can still enforce your choice by setting the chosen application type to SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE).

The “Spring WebFlux Framework”

那么如何根据题目提供的代码实现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 中构建一个合适的 webclient 并将其 Autowiring 到它的类中。

关于java - Spring 启动 : How to use WebClient instead of RestTemplate for Performing Non blocking and Asynchronous calls,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57355725/

相关文章:

java - Cassandra 轻量级事务 rpc_timeout

Java:允许向 java.awt.image 添加自定义类吗?

java - Spring 社会融合

java - 收到错误消息说类未与命名查询映射

Java:为什么我的字符串会通过 UDP 损坏?

Java swing - 多个选项卡的一个搜索框

java - IllegalArgumentException 和 BeanCreationException : No property found for type error

java - 如何在 Spring Boot 中指定回退请求映射

Spring-Cloud、Hystrix 和 JPA - LazyInitializationException

java - Spring如何管理Date参数?