FROM: https://howtodoinjava.com/spring/spring-restful/resttemplate-httpclient-java-config/
<header class="entry-header" style="box-sizing: border-box; display: block; color: rgb(68, 68, 68); font-family: "Open Sans", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
RestTemplate with HttpClient – Java Configuration Example
<time class="entry-time" itemprop="datePublished" datetime="2018-04-21T17:54:05+00:00" style="box-sizing: border-box;">April 21, 2018</time> by Lokesh Gupta
</header>
We have already gone through the RestTemplate examples for accessing REST APIs inside spring application. In this example, we are extending the configuration to use Apache HttpClient 4.
The purpose of this tutorial is to give you pre-cooked recipe for little head-start, and save you from writing all bits and pieces, which really takes lots of time.
HttpClient Configuration
In HttpClientConfig
class, we are configuring mainly two things –
-
[PoolingHttpClientConnectionManager](https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html)
– As name suggest, its connection pool manager. Here, connections are pooled on a per route basis. A request for a route which already the manager has persistent connections for available in the pool will be services by leasing a connection from the pool rather than creating a brand new connection.[ConnectionKeepAliveStrategy](https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/ConnectionKeepAliveStrategy.html)
helps in setting time which decide how long a connection can remain idle before being reused. -
And set a
idleConnectionMonitor
thread, which periodically check all connections and free up which have not been used and idle time has elapsed.
The real http client to use is [CloseableHttpClient](https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/CloseableHttpClient.html)
bean. It is what RestTemplate
will use to get the connection to API endpoints.
<caption style="box-sizing: border-box; padding-top: 8px; padding-bottom: 8px; color: rgb(119, 119, 119); text-align: left;">HttpClientConfig.java</caption>
|
package
com.howtodoinjava.config;
import
java.security.KeyManagementException;
import
java.security.KeyStoreException;
import
java.security.NoSuchAlgorithmException;
import
java.util.concurrent.TimeUnit;
import
org.apache.http.HeaderElement;
import
org.apache.http.HeaderElementIterator;
import
org.apache.http.HttpResponse;
import
org.apache.http.client.config.RequestConfig;
import
org.apache.http.config.Registry;
import
org.apache.http.config.RegistryBuilder;
import
org.apache.http.conn.ConnectionKeepAliveStrategy;
import
org.apache.http.conn.socket.ConnectionSocketFactory;
import
org.apache.http.conn.socket.PlainConnectionSocketFactory;
import
org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import
org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import
org.apache.http.impl.client.CloseableHttpClient;
import
org.apache.http.impl.client.HttpClients;
import
org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import
org.apache.http.message.BasicHeaderElementIterator;
import
org.apache.http.protocol.HTTP;
import
org.apache.http.protocol.HttpContext;
import
org.apache.http.ssl.SSLContextBuilder;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.springframework.context.annotation.Bean;
import
org.springframework.context.annotation.Configuration;
import
org.springframework.scheduling.annotation.EnableScheduling;
import
org.springframework.scheduling.annotation.Scheduled;
/**
* - Supports both HTTP and HTTPS
* - Uses a connection pool to re-use connections and save overhead of creating connections.
* - Has a custom connection keep-alive strategy (to apply a default keep-alive if one isn't specified)
* - Starts an idle connection monitor to continuously clean up stale connections.
*/
@Configuration
@EnableScheduling
public
class
HttpClientConfig {
private
static
final
Logger LOGGER = LoggerFactory.getLogger(HttpClientConfig.``class``);
// Determines the timeout in milliseconds until a connection is established.
private
static
final
int
CONNECT_TIMEOUT = ``30000``;
// The timeout when requesting a connection from the connection manager.
private
static
final
int
REQUEST_TIMEOUT = ``30000``;
// The timeout for waiting for data
private
static
final
int
SOCKET_TIMEOUT = ``60000``;
private
static
final
int
MAX_TOTAL_CONNECTIONS = ``50``;
private
static
final
int
DEFAULT_KEEP_ALIVE_TIME_MILLIS = ``20
* ``1000``;
private
static
final
int
CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS = ``30``;
@Bean
public
PoolingHttpClientConnectionManager poolingConnectionManager() {
SSLContextBuilder builder = ``new
SSLContextBuilder();
try
{
builder.loadTrustMaterial(``null``, ``new
TrustSelfSignedStrategy());
} ``catch
(NoSuchAlgorithmException | KeyStoreException e) {
LOGGER.error(``"Pooling Connection Manager Initialisation failure because of "``+ e.getMessage(), e);
}
SSLConnectionSocketFactory sslsf = ``null``;
try
{
sslsf = ``new
SSLConnectionSocketFactory(builder.build());
} ``catch
(KeyManagementException | NoSuchAlgorithmException e) {
LOGGER.error(``"Pooling Connection Manager Initialisation failure because of "``+ e.getMessage(), e);
}
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory>create().register(``"https"``, sslsf)
.register(``"http"``, ``new
PlainConnectionSocketFactory())
.build();
PoolingHttpClientConnectionManager poolingConnectionManager = ``new``PoolingHttpClientConnectionManager(socketFactoryRegistry);
poolingConnectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS);
return
poolingConnectionManager;
}
@Bean
public
ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
return
new
ConnectionKeepAliveStrategy() {
@Override
public
long
getKeepAliveDuration(HttpResponse response, HttpContext context) {
HeaderElementIterator it = ``new
BasicHeaderElementIterator
(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while
(it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if
(value != ``null
&& param.equalsIgnoreCase(``"timeout"``)) {
return
Long.parseLong(value) * ``1000``;
}
}
return
DEFAULT_KEEP_ALIVE_TIME_MILLIS;
}
};
}
@Bean
public
CloseableHttpClient httpClient() {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(REQUEST_TIMEOUT)
.setConnectTimeout(CONNECT_TIMEOUT)
.setSocketTimeout(SOCKET_TIMEOUT).build();
return
HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(poolingConnectionManager())
.setKeepAliveStrategy(connectionKeepAliveStrategy())
.build();
}
@Bean
public
Runnable idleConnectionMonitor(``final
PoolingHttpClientConnectionManager connectionManager) {
return
new
Runnable() {
@Override
@Scheduled``(fixedDelay = ``10000``)
public
void
run() {
try
{
if
(connectionManager != ``null``) {
LOGGER.trace(``"run IdleConnectionMonitor - Closing expired and idle connections..."``);
connectionManager.closeExpiredConnections();
connectionManager.closeIdleConnections(CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS, TimeUnit.SECONDS);
} ``else
{
LOGGER.trace(``"run IdleConnectionMonitor - Http Client Connection manager is not initialised"``);
}
} ``catch
(Exception e) {
LOGGER.error(``"run IdleConnectionMonitor - Exception occurred. msg={}, e={}"``, e.getMessage(), e);
}
}
};
}
}
|
RestTemplate Configuration
Here we are configuring RestTemplate
bean which we will finally use to invoke REST APIs. As mentioned above, it uses CloseableHttpClient
bean instance to build [ClientHttpRequestFactory](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/ClientHttpRequestFactory.html)
, which is used to create RestTemplate
.
-
[HttpComponentsClientHttpRequestFactory](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.html)
isClientHttpRequestFactory
implementation that uses Apache HttpComponents HttpClient to create requests. - We have used
@Scheduled
annotation inhttpClient
configuration. To support this, we have to add support of scheduled execution of thread. For that, we have used beanThreadPoolTaskScheduler
which internally utilizes ScheduledThreadPoolExecutor to schedule commands to run after a given delay, or to execute periodically.
<caption style="box-sizing: border-box; padding-top: 8px; padding-bottom: 8px; color: rgb(119, 119, 119); text-align: left;">RestTemplateConfig.java</caption>
|
package
com.howtodoinjava.config;
import
org.apache.http.impl.client.CloseableHttpClient;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.context.annotation.Bean;
import
org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import
org.springframework.scheduling.TaskScheduler;
import
org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import
org.springframework.web.client.RestTemplate;
public
class
RestTemplateConfig {
@Autowired
CloseableHttpClient httpClient;
@Bean
public
RestTemplate restTemplate() {
RestTemplate restTemplate = ``new
RestTemplate(clientHttpRequestFactory());
return
restTemplate;
}
@Bean
public
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = ``new``HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setHttpClient(httpClient);
return
clientHttpRequestFactory;
}
@Bean
public
TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = ``new
ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix(``"poolScheduler"``);
scheduler.setPoolSize(``50``);
return
scheduler;
}
}
|
How to use RestTemplate
To use above configured RestTemplate
, simply inject it to controller or test class.
<caption style="box-sizing: border-box; padding-top: 8px; padding-bottom: 8px; color: rgb(119, 119, 119); text-align: left;">TestApplication.java</caption>
|
package
com.howtodoinjava;
import
org.junit.Assert;
import
org.junit.Test;
import
org.junit.runner.RunWith;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.test.context.ContextConfiguration;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import
org.springframework.web.client.RestTemplate;
import
com.howtodoinjava.config.HttpClientConfig;
import
com.howtodoinjava.config.RestTemplateConfig;
@RunWith``(SpringJUnit4ClassRunner.``class``)
@ContextConfiguration``(classes = { RestTemplateConfig.``class``, HttpClientConfig.``class
})
public
class
TestApplication {
@Autowired
RestTemplate restTemplate;
@Test
public
void
getEmployees() {
final
String uri = ``"[http://localhost:8080/employees](http://localhost:8080/employees)"``;
String result = restTemplate.getForObject(uri, String.``class``);
Assert.assertEquals(``true``, result.indexOf(``"Lokesh"``) > ``0``);
}
}
|
Maven Dependencies
Primarily, you will be required to have two dependencies i.e. httpclient
and spring-web
. I am using spring boot application, so the pom file looks like this:
<caption style="box-sizing: border-box; padding-top: 8px; padding-bottom: 8px; color: rgb(119, 119, 119); text-align: left;">pom.xml</caption>
|
<``project
xmlns``=``"[http://maven.apache.org/POM/4.0.0](http://maven.apache.org/POM/4.0.0)"``xmlns:xsi``=``"[http://www.w3.org/2001/XMLSchema-instance](http://www.w3.org/2001/XMLSchema-instance)"
xsi:schemaLocation``=``"[http://maven.apache.org/POM/4.0.0](http://maven.apache.org/POM/4.0.0)[http://maven.apache.org/xsd/maven-4.0.0.xsd](http://maven.apache.org/xsd/maven-4.0.0.xsd)"``>
<``modelVersion``>4.0.0</``modelVersion``>
<``groupId``>com.howtodoinjava</``groupId``>
<``artifactId``>springbootdemo</``artifactId``>
<``version``>0.0.1-SNAPSHOT</``version``>
<``packaging``>jar</``packaging``>
<``name``>springbootdemo</``name``>
<``url``>[http://maven.apache.org](http://maven.apache.org/)</``url``>
<``parent``>
<``groupId``>org.springframework.boot</``groupId``>
<``artifactId``>spring-boot-starter-parent</``artifactId``>
<``version``>2.0.0.RELEASE</``version``>
</``parent``>
<``properties``>
<``java.version``>1.8</``java.version``>
<``project.build.sourceEncoding``>UTF-8</``project.build.sourceEncoding``>
</``properties``>
<``dependencies``>
<``dependency``>
<``groupId``>org.springframework.boot</``groupId``>
<``artifactId``>spring-boot-starter-web</``artifactId``>
</``dependency``>
<``dependency``>
<``groupId``>org.springframework.boot</``groupId``>
<``artifactId``>spring-boot-starter-hateoas</``artifactId``>
</``dependency``>
<``dependency``>
<``groupId``>org.springframework.boot</``groupId``>
<``artifactId``>spring-boot-starter-test</``artifactId``>
</``dependency``>
<``dependency``>
<``groupId``>org.apache.httpcomponents</``groupId``>
<``artifactId``>httpclient</``artifactId``>
</``dependency``>
</``dependencies``>
<``build``>
<``plugins``>
<``plugin``>
<``groupId``>org.springframework.boot</``groupId``>
<``artifactId``>spring-boot-maven-plugin</``artifactId``>
</``plugin``>
</``plugins``>
</``build``>
</``project``>
|
References:
HttpClient Docs
Spring RestTemplate class
网友评论