Implementing REST Service Calls in Spring Boot: RestTemplate vs WebClient

Overview

Spring Boot provides two distinct mechanisms for envoking remote REST services: the traditional RestTemplate and the reactive WebClient. This guide explores configuration and customization strategies for both approaches.

RestTemplate Implementation

Required Dependencies

RestTemplate is part of the Spring Web module and gets auto-configured when you include the web starter:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

The auto-configuration class RestTemplateAutoConfiguration registers a RestTemplateBuilder bean automatically, which serves as the foundation for creating customized instances.

Custom Configuration

Build a tailored RestTemplate instance using the builder pattern to define timeouts and interceptors:

@Bean
public RestTemplate configuredRestTemplate(RestTemplateBuilder builder) {
    return builder
            .setConnectTimeout(Duration.ofSeconds(10))
            .setReadTimeout(Duration.ofSeconds(10))
            .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer custom-token")
            .build();
}

Advanced Customization with HttpClient

For sophisticated scenarios requiring proxy routing or connection pooling, implement a RestTemplateCustomizer:

@Slf4j
@Component
public class ProxyAwareRestTemplateCustomizer implements RestTemplateCustomizer {

    @Override
    public void customize(RestTemplate template) {
        HttpHost proxyHost = new HttpHost("gateway.example.com", 8080);
        HttpRoutePlanner routePlanner = new DynamicRoutePlanner(proxyHost);
        
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(100);
        connectionManager.setDefaultMaxPerRoute(20);
        
        CloseableHttpClient httpClient = HttpClientBuilder.create()
                .setConnectionManager(connectionManager)
                .setRoutePlanner(routePlanner)
                .build();
                
        template.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
    }

    static class DynamicRoutePlanner extends DefaultProxyRoutePlanner {
        
        public DynamicRoutePlanner(HttpHost proxy) {
            super(proxy);
        }
        
        @Override
        protected HttpHost determineProxy(HttpHost target, HttpContext context) throws HttpException {
            String hostname = target.getHostName();
            log.debug("Evaluating route for host: {}", hostname);
            
            // Bypass proxy for internal services
            if (hostname.endsWith(".internal.local")) {
                return null;
            }
            return super.determineProxy(target, context);
        }
    }
}

WebClient Implemantation

Required Dependencies

WebClient belongs to the reactive stack and requires the WebFlux starter:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

The WebClientAutoConfiguration class automatically provides a WebClient.Builder bean for streamlined instantiation.

Custom Configuration

Create a reactive client with fine-grained control over network parameters:

@Bean
public WebClient customWebClient(WebClient.Builder builder) {
    TcpClient tcpClient = TcpClient.create()
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
            .doOnConnected(connection -> {
                connection.addHandler("readTimeout", new ReadTimeoutHandler(5));
                connection.addHandler("writeTimeout", new WriteTimeoutHandler(5));
            });
    
    ClientHttpConnector connector = new ReactorClientHttpConnector(
            HttpClient.from(tcpClient).wiretap(true)
    );
    
    return builder
            .clientConnector(connector)
            .defaultHeader(HttpHeaders.USER_AGENT, "ReactiveClient/1.0")
            .build();
}

Note: When building multiple WebClient instances with distinct configurations, invoke builder.clone() before applying custom settings to prevent shared state issues.

Tags: spring-boot RestTemplate webclient WebFlux apache-httpclient

Posted on Thu, 20 Aug 2026 16:58:03 +0000 by biba028