Search code examples
spring-bootresttemplatespring-webfluxproject-reactor

Spring WebClient as an alternative to RestTemplate


The current javadoc of RestTemplate states:

NOTE: As of 5.0, the non-blocking, reactive org.springframework.web.reactive.client.WebClient offers a modern alternative to the RestTemplate with efficient support for both sync and async, as well as streaming scenarios. The RestTemplate will be deprecated in a future version and will not have major new features added going forward.

We are writing a new project using spring boot 2.0.6 and spring 5.0.10.

Seeing that restTemplate is going to be deprecated we decided to use the new WebClient which should have support for synch calls as well. But I couldn't find any documentation on how that should be achieved.

I have used block for this as in the code below:

ResponseEntity<String> response = webClient.get()
            .uri(url)
            .exchange()
            .flatMap(r -> r.toEntity(String.class))
            .block();

However this is throwing the exception below when called from a spring controller

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread

So how exactly should WebClient be used in a synchronous way?

EDIT: My pom.xml looks like this:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>

Solution

  • If your application is just using spring-boot-starter-webflux, it means both the server and client will be using Spring WebFlux. In this case, it is forbidden to call a block operator within a Controller handler, as it will block one of the few server threads and will create important runtime issues.

    If the main driver behind this is to use WebClient, then you can depend on both spring-boot-starter-web and spring-boot-starter-webflux. Your Spring Boot application will still use Spring MVC on the server side and you'll be able to use WebClient as a client. In that case, you can call block operators or even use Flux or Mono as return types in your controllers, as Spring MVC supports that. You can even gradually introduce WebClient in an existing Spring MVC application.