In order to configure RestTemplate I use the following configuration:
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault());
httpRequestFactory.setConnectTimeout(connectionTimeoutMs);
httpRequestFactory.setConnectionRequestTimeout(readTimeoutMs);
httpRequestFactory.setReadTimeout(readTimeoutMs);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
I understand the purpose of connection and read timeouts. But I don't understand the purpose of connection request timeout. It also not clear from Javadoc what does it mean. Could you please explain it ?
As the docs say :
Set the timeout in milliseconds used when requesting a connection from
the connection manager using the underlying HttpClient.
It means the maximum amount of time you will allow to the connection manager to give you an available connection from its pool (so it has nothing to do with the RESTservice itself you'll reach).
To define a custom connection manager, you can use this :
CloseableHttpClient httpClientBuilder = HttpClientBuilder.create().setConnectionManager(...).build();
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClientBuilder);
Related
I have a restemplate which can make call to multiple external systems over https.
I configured the resttemplate like so :
SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(key, keyPassword)
.build();
HttpClient client = HttpClients
.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
client);
httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
httpComponentsClientHttpRequestFactory.setReadTimeout(30000);
return new RestTemplate(httpComponentsClientHttpRequestFactory);
I have setup 2 mock services on 2 separate VMs with ssl enabled and I am testing this restemplate by calling those services over https. And it works.
What I want to confirm is that configuring the restemplate as shown in the above code and importing the certificates of the different services to be called in by the client truststore should work without any additional configurations right?
I am confused because in the code in this example here : https://github.com/jonashackt/spring-boot-rest-clientcertificates-docker-compose the author has used 2 different factories i.e. serverTomClientHttpRequestFactory & serverAliceClientHttpRequestFactory, however mine works with a single restemplate. can someone please shed some light on this topic?
I'd like to monitor the connection pool of a Apache httpComponents PoolingHttpClientConnectionManager but cannot find a way to access it.
We create our HttpClient using the following builder:
HttpClient httpClient = HttpClientBuilder.create()
.setMaxConnTotal(maxConnections)
.setMaxConnPerRoute(maxConnectionsPerRoute)
.build();
This creates an instance of an InternalHttpClient, which holds an instance of a PoolingHttpClientConnectionManager, which holds an instance of a CPool.
CPool would give us access to T getRoutes() and PoolStats getStats(T) — which looks promising to me. But I can't really find out how to get access to this CPool.
HttpClient.getConnectionManager() is deprecated. InternalHttpClient.getConnectionManager() is not deprecated, but returns a custom connection manager, which only exposes some of the methods of the real connection manager instance behind it.
So, how to get access to these stats? These would be very helpful for us.
Use ConnPoolControl implemented by PoolingHttpClientConnectionManager
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
ConnPoolControl<HttpRoute> connPoolControl = cm;
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(cm)
.build();
I am using Spring WebFlux and WebClient for my web application.
My application potentially can call a 'N' number of other micro services which is also hosted by us.
Now the problem is that i want to restrict my WebClient to invoke a limited number of simultaneous calls to the existing micro services.
Also, I don't want to do it at individual call level, but at application level.
I have already gone through "How to limit the number of active Spring WebClient calls?" and "How to limit the request/second with WebClient?", to no avail.
You can create a WebClient instance like this:
ConnectionProvider fixedPool = ConnectionProvider.fixed("fixedPool", maxConnections, acquireTimeout);
HttpClient httpClient = HttpClient.create(fixedPool);
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient)).build();
Since reactor-netty 0.9.5, the method described by Brian Clozel is now deprecated, use instead:
ConnectionProvider fixedPool = ConnectionProvider.builder("fixedPool")
.maxConnections(200)
.pendingAcquireTimeout(Duration.ofMinutes(3))
.build();
HttpClient httpClient = HttpClient.create(fixedPool);
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
max connectiond and pending acquire timeout are random values, change them according to your needs.
Just wondering if RestTemplate out of the box uses connection pooling or does it simply establish a new connection each time ?
Yes, Spring RestTemplateBuilder uses Apache HttpClient for pooling (usage).
RestTemplateBuilder creates HttpComponentsClientHttpRequestFactory and uses HttpClientBuilder.
HttpClientBuilder, by default, sets pool size per route (host) to 5 and total pool size to 10 (source):
s = System.getProperty("http.maxConnections", "5");
int max = Integer.parseInt(s);
poolingmgr.setDefaultMaxPerRoute(max);
poolingmgr.setMaxTotal(2 * max);
To check connection pool logging set logging level as follows:
org.apache.http.impl.conn.PoolingHttpClientConnectionManager=TRACE
I believe RestTemplate doesn’t use a connection pool to send requests, it uses a SimpleClientHttpRequestFactory that wraps a standard JDK’s HttpURLConnection opening and closing the connection.
Indeed you can configure RestTemplate to use a pooled implementation such as HttpComponentsClientHttpRequestFactory but most-likely you might also need to configure some settings to prevent requests from timing out.
I have blogged about this issue at Troubleshooting Spring's RestTemplate Requests Timeout
By default RestTemplate creates new Httpconnection every time and closes the connection once done.
If you need to have a connection pooling under rest template then you may use different implementation of the ClientHttpRequestFactory that pools the connections.
new RestTemplate(new HttpComponentsClientHttpRequestFactory())
You can create a Bean for RestTemplate and config there :
#Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(20);
RequestConfig requestConfig = RequestConfig
.custom()
.setConnectionRequestTimeout(5000) // timeout to get connection from pool
.setSocketTimeout(5000) // standard connection timeout
.setConnectTimeout(5000) // standard connection timeout
.build();
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(requestFactory);
}
And there are a lot config you can do. Refer to https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/HttpClientBuilder.html
EDIT
If you want to use micrometer metrics you should also use a RestTemplateBuilder for constructing the RestTemplate.
In case of using Spring Boot configured with Apache HttpClient (having org.apache.httpcomponents:httpclient library in dependencies)
There is a default connection pool configured by PoolingHttpClientConnectionManager
Default concurrent settings for connections (you can find more about default settings here https://hc.apache.org/httpcomponents-client-4.5.x/current/tutorial/html/connmgmt.html):
PoolingHttpClientConnectionManager maintains a maximum limit of connections on a per route basis and in total. Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total. For many real-world applications these limits may prove too constraining, especially if they use HTTP as a transport protocol for their services.
We can use okhttpclient underneath spring's rest template to use connection pooling. A detailed blog on this below
https://www.bytesville.com/changing-httpclient-in-spring-resttemplate/
my resttemplate.exchange() failed on a POST request, with the server returning a 500 error.
I tried to set the root logging level to DEBUG, but nothing was logged before the 500 error was returned. to make sure that my logging config is right, I added a line before the resttemplate call
HttpClient client = new DefaultHttpClient();
client.execute(new HttpGet("http://google.com"));
in this case indeed a lot of logging messages appeared.
so how can I make RestTemplate export the debugging data?
Thanks
Yang
From your analysis it seems that you expect RestTemplate to use Apache HttpClient.
However, by default, Spring RestTemplate does not use Apache HttpClient but uses the JDK facilities (java.net.URL#openConnection() etc.) by means of SimpleClientHttpRequestFactory.
org.springframework.http.client.support.HttpAccessor declares:
private ClientHttpRequestFactory requestFactory = new
SimpleClientHttpRequestFactory();
As far as I know, this client does not support logging requests/responses.
To change RestTemplate to use HttpClient, try this:
new RestTemplate(new HttpComponentsClientHttpRequestFactory());
Logging configuration should then enable category org.apache.http.wire at level debug for complete requests/responses to be logged.