Search results
Register multiple RestTemplate Beans with Spring's ApplicationContext Programmatically
application.yml
:
asimiotech:
rest-templates:
-
bean-id: restTemplate1
max-total: 20
default-max-per-route: 20
conn-timeout-millis: 4000
conn-request-timeout-millis: 4000
socket-timeout-millis: 4000
routes:
-
scheme: http
host: localhost
port: 8000
max-per-route: 20
-
bean-id: restTemplate2
max-total: 10
default-max-per-route: 10
conn-timeout-millis: 2000
conn-request-timeout-millis: 2000
socket-timeout-millis: 2000
routes:
-
scheme: http
host: localhost
port: 8080
max-per-route: 10
AsimioTechProperties.java
:
@ConfigurationProperties(prefix = "asimiotech")
@Getter
@Setter
public class AsimioTechProperties {
private List<RestTemplateProperties> restTemplates;
@Getter
@Setter
public static class RestTemplateProperties {
private String beanId;
private Integer maxTotal;
private Integer defaultMaxPerRoute;
private Integer connTimeoutMillis;
private Integer connRequestTimeoutMillis;
private Integer socketTimeoutMillis;
private List<RouteProperties> routes;
}
@Getter
@Setter
public static class RouteProperties {
private String scheme;
private String host;
private Integer port;
private Integer maxPerRoute;
}
}
RestTemplateConfig.java
:
@Configuration
@EnableConfigurationProperties(AsimioTechProperties.class)
@RequiredArgsConstructor
public class RestTemplateConfig {
private final GenericApplicationContext applicationContext;
private final AsimioTechProperties asimioTechProperties;
@PostConstruct
public void registerRestTemplateBeans() {
this.asimioTechProperties.getRestTemplates().stream()
.forEach(restTemplateProps -> this.registerRestTemplateBeans(restTemplateProps));
}
private void registerRestTemplateBeans(AsimioTechProperties.RestTemplateProperties restTemplateProps) {
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = this.registerPoolingHttpClientConnectionManagerBean(restTemplateProps);
RequestConfig requestConfig = this.registerRequestConfigBean(restTemplateProps);
CloseableHttpClient httpClient = this.registerApacheHttpClientBean(poolingHttpClientConnectionManager, requestConfig, restTemplateProps);
this.registerRestTemplateBean(httpClient, restTemplateProps);
}
private PoolingHttpClientConnectionManager registerPoolingHttpClientConnectionManagerBean(AsimioTechProperties.RestTemplateProperties restTemplateProps) {
PoolingHttpClientConnectionManager result = this.poolingHttpClientConnectionManager(restTemplateProps);
this.applicationContext.registerBean(
String.format("poolingHttpClientConnectionManager%s", StringUtils.capitalize(restTemplateProps.getBeanId())),
PoolingHttpClientConnectionManager.class,
() -> result
);
return result;
}
private PoolingHttpClientConnectionManager poolingHttpClientConnectionManager(
AsimioTechProperties.RestTemplateProperties restTemplateProps) {
PoolingHttpClientConnectionManager result = new PoolingHttpClientConnectionManager();
result.setMaxTotal(restTemplateProps.getMaxTotal());
// Default max per route is used in case it's not set for a specific route
result.setDefaultMaxPerRoute(restTemplateProps.getDefaultMaxPerRoute());
// Adding individual route configuration when they exist
restTemplateProps.getRoutes().stream()
.forEach(route -> this.addNewRoute(result, route));
return result;
}
private void addNewRoute(PoolingHttpClientConnectionManager connectionManager, RouteProperties route) {
HttpHost host = new HttpHost(route.getScheme(), route.getHost(), route.getPort());
// Max per route for a specific host route
connectionManager.setMaxPerRoute(new HttpRoute(host), route.getMaxPerRoute());
}
private RequestConfig registerRequestConfigBean(AsimioTechProperties.RestTemplateProperties restTemplateProps) {
RequestConfig result = this.requestConfig(restTemplateProps);
this.applicationContext.registerBean(
String.format("requestConfig%s", StringUtils.capitalize(restTemplateProps.getBeanId())),
RequestConfig.class,
() -> result
);
return result;
}
private RequestConfig requestConfig(AsimioTechProperties.RestTemplateProperties restTemplateProps) {
RequestConfig result = RequestConfig.custom()
.setConnectionRequestTimeout(restTemplateProps.getConnRequestTimeoutMillis(), TimeUnit.MILLISECONDS)
.setConnectTimeout(restTemplateProps.getConnTimeoutMillis(), TimeUnit.MILLISECONDS)
.setResponseTimeout(restTemplateProps.getSocketTimeoutMillis(), TimeUnit.MILLISECONDS)
.build();
return result;
}
private CloseableHttpClient registerApacheHttpClientBean(
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager,
RequestConfig requestConfig,
AsimioTechProperties.RestTemplateProperties restTemplateProps) {
CloseableHttpClient result = this.apacheHttpClient(poolingHttpClientConnectionManager, requestConfig);
this.applicationContext.registerBean(
String.format("closeableHttpClient%s", StringUtils.capitalize(restTemplateProps.getBeanId())),
CloseableHttpClient.class,
() -> result
);
return result;
}
private CloseableHttpClient apacheHttpClient(
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager,
RequestConfig requestConfig) {
CloseableHttpClient result = HttpClientBuilder.create()
.setConnectionManager(poolingHttpClientConnectionManager)
.setDefaultRequestConfig(requestConfig)
.build();
return result;
}
private RestTemplate registerRestTemplateBean(
HttpClient httpClient,
AsimioTechProperties.RestTemplateProperties restTemplateProps) {
RestTemplate result = this.restTemplate(httpClient);
this.applicationContext.registerBean(restTemplateProps.getBeanId(), RestTemplate.class, () -> result);
return result;
}
private RestTemplate restTemplate(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
}
Usage
ClassThatSendsHttpRequests.java
:
@RequiredArgsConstructor
public class ClassThatSendsHttpRequests {
@Qualifier("restTemplate1")
private final RestTemplate restTemplate1;
// ...
}
and
AnotherClassThatSendsHttpRequests.java
:
@RequiredArgsConstructor
public class AnotherClassThatSendsHttpRequests {
@Qualifier("restTemplate2")
private final RestTemplate restTemplate2;
// ...
}
or
SomeClassThatSendsHttpRequests.java
:
@RequiredArgsConstructor
public class SomeClassThatSendsHttpRequests {
@Qualifier("restTemplate1")
private final RestTemplate restTemplate1;
@Qualifier("restTemplate2")
private final RestTemplate restTemplate2;
// ...
}
Warning:
This approach doesn’t work, nor cover reloading properties changes and refreshing relevant Spring Beans using @RefreshScope annotation.
Warning:
Read on if you are interested in learning how RestTemplate’s wrong configuration leads to RestTemplate Requests Timeout.
Also related to this page:
Recipe to configure a single RestTemplate Bean with Apache HttpClient 5 Connection Pool
Recipe to configure a single RestTemplate Bean with Apache HttpClient 5 Connection Pool
Source code at: