Backend Development 9 min read

Mastering Spring Boot RestTemplate and WebClient: Configuration and Customization

Learn how Spring Boot 2.6.14 simplifies calling remote REST services using RestTemplate and WebClient, including automatic configuration with RestTemplateBuilder, customization options via RestTemplateCustomizer and WebClient.Builder, and detailed code examples for building, customizing, and selecting appropriate HTTP connectors.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Spring Boot RestTemplate and WebClient: Configuration and Customization

Environment: Spring Boot 2.6.14

RestTemplate

When an application needs to call a remote REST service, Spring Boot provides RestTemplate (or the reactive WebClient ) for convenient access.

RestTemplate instances usually require customization before use, so Spring Boot does not expose a single auto‑configured RestTemplate bean. Instead, it auto‑configures a RestTemplateBuilder that can create RestTemplate instances with sensible HttpMessageConverters .

<code>@Service
public class RemoteService {
  private final RestTemplate restTemplate;

  public RemoteService(RestTemplateBuilder restTemplateBuilder) {
    this.restTemplate = restTemplateBuilder.build();
  }

  public Details storageService(Long storageId, Integer count) {
    return this.restTemplate.getForObject(
      "http://localhost:8080/storage/deduct/{storageId}/{count}",
      Boolean.class, storageId, count);
  }
}
</code>
RestTemplateBuilder includes many useful methods for quick configuration. For example, to add BASIC authentication support you can use builder.basicAuthentication("admin", "123").build() .

Customizing RestTemplate

There are three main ways to customize RestTemplate, depending on the desired scope:

For the narrowest scope, inject the auto‑configured RestTemplateBuilder and call its methods; each call returns a new builder instance, so customization only affects that usage.

For application‑wide additional customization, define a RestTemplateCustomizer bean. All such beans are automatically registered with the auto‑configured RestTemplateBuilder and applied to any RestTemplate built from it.

For the most extreme case, define your own RestTemplateBuilder bean, replacing the auto‑configuration entirely.

Auto‑configuration example

<code>public class RestTemplateAutoConfiguration {
  @Bean
  @Lazy
  @ConditionalOnMissingBean
  public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer restTemplateBuilderConfigurer) {
    RestTemplateBuilder builder = new RestTemplateBuilder();
    return restTemplateBuilderConfigurer.configure(builder);
  }
}
</code>

Custom RestTemplateCustomizer

<code>public class CustomRestTemplateCustomizer implements RestTemplateCustomizer {

  @Override
  public void customize(RestTemplate restTemplate) {
    restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
  }
}
</code>

Defining a custom RestTemplateBuilder bean

<code>@Configuration(proxyBeanMethods = false)
public class CustomRestTemplateBuilderConfiguration {

  @Bean
  public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer configurer) {
    return configurer.configure(new RestTemplateBuilder())
      .setConnectTimeout(Duration.ofSeconds(5))
      .setReadTimeout(Duration.ofSeconds(2));
  }
}
</code>

Spring Boot also provides a default RestTemplateBuilderConfigurer that configures sensible HttpMessageConverters.

WebClient

If Spring WebFlux is on the classpath, you can use the reactive WebClient instead of RestTemplate. WebClient offers richer functionality and full reactive support.

Spring Boot auto‑configures a WebClient.Builder . It is recommended to inject this builder into components and use it to create WebClient instances, sharing HTTP resources and codec settings.

<code>@Service
public class WebClientService {
  private final WebClient webClient;

  public WebClientService(WebClient.Builder webClientBuilder) {
    this.webClient = webClientBuilder.baseUrl("http://localhost:8080").build();
  }

  public Mono<Details> storageService(Long storageId, Integer count) {
    return this.webClient.get()
      .uri("/storage/deduct/{storageId}/{count}", storageId, count)
      .retrieve()
      .bodyToMono(Boolean.class);
  }
}
</code>

WebClient runtime

Spring Boot automatically detects which ClientHttpConnector to use based on the libraries present on the classpath. Supported connectors include Reactor Netty, Jetty, and Apache HttpClient.

WebClient source snippet

<code>public interface WebClient {
  static WebClient.Builder builder() {
    return new DefaultWebClientBuilder();
  }
}

final class DefaultWebClientBuilder implements WebClient.Builder {
  private static final boolean reactorClientPresent;
  private static final boolean jettyClientPresent;
  private static final boolean httpComponentsClientPresent;

  static {
    ClassLoader loader = DefaultWebClientBuilder.class.getClassLoader();
    reactorClientPresent = ClassUtils.isPresent("reactor.netty.http.client.HttpClient", loader);
    jettyClientPresent = ClassUtils.isPresent("org.eclipse.jetty.client.HttpClient", loader);
    httpComponentsClientPresent = ClassUtils.isPresent("org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient", loader) &&
      ClassUtils.isPresent("org.apache.hc.core5.reactive.ReactiveDataConsumer", loader);
  }

  public WebClient build() {
    ClientHttpConnector connectorToUse = (this.connector != null ? this.connector : initConnector());
    // ...
    return new DefaultWebClient(...);
  }

  private ClientHttpConnector initConnector() {
    if (reactorClientPresent) {
      return new ReactorClientHttpConnector();
    } else if (jettyClientPresent) {
      return new JettyClientHttpConnector();
    } else if (httpComponentsClientPresent) {
      return new HttpComponentsClientHttpConnector();
    }
    throw new IllegalStateException("No suitable default ClientHttpConnector found");
  }
}
</code>

The default spring-boot-starter-webflux starter pulls in io.projectreactor.netty:reactor-netty , which provides both server and client implementations. If Jetty is chosen as the reactive server, a Jetty client dependency should also be added to keep client and server implementations consistent.

Developers can override the default resources by providing custom ReactorResourceFactory or JettyResourceFactory beans, affecting both client and server.

To fully control the client configuration, define a custom ClientHttpConnector bean.

WebClient customization

Inject the auto‑configured WebClient.Builder and call its methods for narrow‑scope customizations; the builder is stateful, so changes affect all clients created from it. Use WebClient.Builder other = builder.clone(); to create independent clients.

For application‑wide customizations, declare a WebClientCustomizer bean that modifies the builder at injection points.

Alternatively, use the raw API WebClient.create() , which bypasses auto‑configuration and any customizers.

End of tutorial.

backendJavaSpring BootHTTPRestTemplateWebClient
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.