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.