Spring RestTemplate - Need to release connection? - spring

This is my Configuration for Rest Template,
#Bean
#Qualifier("myRestService")
public RestTemplate createRestTemplate(#Value("${connection.timeout}") String maxConn) {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(maxTotalConn);
connectionManager.setDefaultMaxPerRoute(maxPerChannel);
RequestConfig config = RequestConfig.custom().setConnectTimeout(100000).build();
CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager)
.setDefaultRequestConfig(config).build();
ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(factory);
restTemplate.setErrorHandler(new RestResponseErrorHandler());
restTemplate.setMessageConverters(createMessageConverters());
return restTemplate;
}
Am using PoolingHttpClientConnectionManager for managing the connections.
Its being accessed by the following code,
ResponseEntity<String> response = restClient.exchange( url, HttpMethod.GET, entity , String.class );
Do i need to release the connection after the above call or is it taken care by RestTemplate. If we need to take care of releasing connection.
Please can some one explain/show how to release the connection.

You should declare the ClientHttpRequestFactory as a bean. By declaring it as a bean, it becomes managed by the Spring bean factory, which will call the factory's destroy method when the application is closed, or the bean goes out of scope. The destroy method of the ClientHttpRequestFactory will close the underlying ClientConnectionManager's connection pool. You can check the Spring API docs for this.
#Bean
public ClientHttpRequestFactory createRequestFactory(#Value("${connection.timeout}") String maxConn) {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(maxTotalConn);
connectionManager.setDefaultMaxPerRoute(maxPerChannel);
RequestConfig config = RequestConfig.custom().setConnectTimeout(100000).build();
CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager)
.setDefaultRequestConfig(config).build();
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
Then you can use this bean to create your RestTemplate:
#Bean
#Qualifier("myRestService")
public RestTemplate createRestTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
restTemplate.setErrorHandler(new RestResponseErrorHandler());
restTemplate.setMessageConverters(createMessageConverters());
return restTemplate;
}

The question which you have asked:
Do i need to release the connection after the above call or is it taken care by RestTemplate. If we need to take care of releasing connection.
No, you do not need to close the connection on the response, if you use resttemplate.
From the apache httpclient, you need to consume the complete response (EntityUtils.consume(HttpEntity) and close the response.
This can be verified in the ClientConnectionRelease.java
But RestTemplate does this for you, to verify the same have a look into
RestTemplate.java
Look for method
protected <T> T doExecute(URI url,...) {
try {
ClientHttpRequest request = this.createRequest(url, method);
...
response = request.execute();
...
if(responseExtractor != null) {
var7 = responseExtractor.extractData(response);
return var7;
}
...
...
} finally {
if(response != null) {
response.close();
}
}
}
Where response extractor does the work for you by consuming the response using
responseExtractor.extractData(response);
And after extracting the data completely it is closing response.close() as well.

I think the answer is here: org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor#doExecuteRequest
#Override
protected RemoteInvocationResult doExecuteRequest(
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
throws IOException, ClassNotFoundException {
HttpPost postMethod = createHttpPost(config);
setRequestBody(config, postMethod, baos);
try {
HttpResponse response = executeHttpPost(config, getHttpClient(), postMethod);
validateResponse(config, response);
InputStream responseBody = getResponseBody(config, response);
return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
}
finally {
postMethod.releaseConnection();
}
}

Related

adding request param to every request using spring resttemplate

I am trying to add common request parameters to every request using RestTemplate.
For example if my url is http://something.com/countries/US then I want to add common request param ?id=12345. This common request parameter needs to be added on all request. I don't want to add this on each call and want something common.
this post has answer that was marked correct, but I am not sure how you can add request parameters on org.springframework.http.HttpRequest
Any other way I can achieve this ?
To add request parameters to the HttpRequest , you can first use UriComponentsBuilder to build an new URI based on the existing URI but adding the query parameters that you want to add.
Then use HttpRequestWrapper to wrap the existing request but only override its URI with the updated URI.
Code wise it looks like:
public class AddQueryParamterInterceptor implements ClientHttpRequestInterceptor {
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
URI uri = UriComponentsBuilder.fromHttpRequest(request)
.queryParam("id", 12345)
.build().toUri();
HttpRequest modifiedRequest = new HttpRequestWrapper(request) {
#Override
public URI getURI() {
return uri;
}
};
return execution.execute(modifiedRequest, body);
}
}
And set this interceptor to the RestTemplate:
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new AddQueryParamterInterceptor());
restTemplate.setInterceptors(interceptors);
Two things are required to add common request parameters to every request using RestTemplate.
Create a prototype bean RestTemplate
#Configuration
public class RestTemplateConfig {
#Bean
#Scope(
value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,
proxyMode = ScopedProxyMode.TARGET_CLASS)
public RestTemplate restTemplate() {
RestTemplate localRestTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = localRestTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new AddQueryParamterInterceptor());
localRestTemplate.setInterceptors(interceptors);
return localRestTemplate;
}
}
Use the Interceptor code as suggested by #ken-chan to add the request parameters. A new instance of Resttemaple will be created and for each and every request.
You can achieve this by adding interceptor to rest template

Getting the request URL of a SOAP request in handleResponse Method in ClientInterceptor

I am using spring boot. I have written a ClientInterceptor for a SOAP web service and i would like to log the URL that i am sending my request to, and i would like to do it in the handleResponse method. However i could not find a way to do it. Is it possible? Any help would be great.
public class SoapClientHttpRequestInterceptor implements ClientInterceptor {
#Override
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
// I would like to get the URL and log it here.
}
}
The way i create the restTemplate
#Bean
#Qualifier("testRestTemplate")
public RestTemplate testRestTemplate() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false);
ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(requestFactory);
RestTemplate restTemplate = new RestTemplate(factory);
restTemplate.setInterceptors(Collections.singletonList(restClientHttpRequestInterceptor));
restTemplate.setErrorHandler(testErrorHandler);
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
You can do this in your handleResponse method:
TransportContext context = TransportContextHolder.getTransportContext();
context.getConnection().getUri().toString()
i hope this helps you

RestTemplate read timeout doesn't work

I have a springboot rest Service A calling rest service B using restTemplate.
Rest service A's restTemplate bean is created as follows with timeout settings as seen in the code snippet below.
#Bean
RestTemplate getRestTemplate()
{
CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(closeableHttpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
requestFactory.setConnectTimeout( 2000 );
requestFactory.setReadTimeout( 2000 );
return restTemplate;
}
A calls B as follows:
try{
restTemplate.postForEntity(urlSvcB, httpEntity, myObject.class);
}
catch (Exception ex){
.....some code here.....
}
When I put both A and B in bebug mode and wait at a breakpoint in B for more than 2 seconds, I except restTemplate call in A to detect a timeout of 2 seconds and straight away go in to the exception block BUT it doesn't. I also put a thread.sleep(5000) in B but still in vain.
Is there anything wrong I am doing because of which I don't see the expected ?
If you are using spring boot, then you could try:
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
{
return restTemplateBuilder
.setConnectTimeout(...)
.setReadTimeout(...)
.build();
}
If that is not okay, then in your current code, try setting all the props on requestFactory before creating a restTemplate OR test once by getting rid of CloseableHTTPClient like:
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectionRequestTimeout(...);
httpRequestFactory.setConnectTimeout(...);
httpRequestFactory.setReadTimeout(...);
return new RestTemplate(httpRequestFactory);

How do I set timeouts per request using Spring REST Template?

I have an application that makes use of multiple rest clients. Each of those REST clients use the same Spring REST template bean. I was wondering if there was a way to set the timeout value per request using the Spring rest template?
This worked for me...
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 5000;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
= new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
return clientHttpRequestFactory;
}
To achieve calling rest template with timeout, first you should create config class also use with #Bean annotation, then implement in class and call with RestTemplateConfig.
#Configuration
public class RestTemplateConfig {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(clientHttpRequestFactory());
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectionRequestTimeout(4000);
clientHttpRequestFactory.setReadTimeout(4000);
clientHttpRequestFactory.setConnectTimeout(4000);
return clientHttpRequestFactory;
}
}
But I suggest you use Apache HttpClient, you can manage the connection pool, keep-alive, idle monitor and also create custom error handler. You can check the link: https://springframework.guru/using-resttemplate-with-apaches-httpclient/
You can also modify the SimpleClientHttpRequestFactory.
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(customHttpRequestFactory());
private SimpleClientHttpRequestFactory customHttpRequestFactory() {
SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
simpleClientHttpRequestFactory.setReadTimeout(2000);
simpleClientHttpRequestFactory.setConnectTimeout(2000);
return simpleClientHttpRequestFactory;
}

Spring RestTemplate timeout

I would like to set the connection timeouts for a rest service used by my web application. I'm using Spring's RestTemplate to talk to my service. I've done some research and I've found and used the xml below (in my application xml) which I believe is meant to set the timeout. I'm using Spring 3.0.
I've also seen the same problem here Timeout configuration for spring webservices with RestTemplate but the solutions don't seem that clean, I'd prefer to set the timeout values via Spring config
<bean id="RestOperations" class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.CommonsClientHttpRequestFactory">
<property name="readTimeout" value="${restURL.connectionTimeout}" />
</bean>
</constructor-arg>
</bean>
It seems whatever I set the readTimeout to be I get the following:
Network cable disconnected:
Waits about 20 seconds and reports following exception:
org.springframework.web.client.ResourceAccessException: I/O error: No route to host: connect; nested exception is java.net.NoRouteToHostException: No route to host: connect
Url incorrect so 404 returned by rest service:
Waits about 10 seconds and reports following exception:
org.springframework.web.client.HttpClientErrorException: 404 Not Found
My requirements require shorter timeouts so I need to be able to change these. Any ideas as to what I'm doing wrong?
Many thanks.
For Spring Boot >= 1.4
#Configuration
public class AppConfig
{
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
{
return restTemplateBuilder
.setConnectTimeout(...)
.setReadTimeout(...)
.build();
}
}
For Spring Boot <= 1.3
#Configuration
public class AppConfig
{
#Bean
#ConfigurationProperties(prefix = "custom.rest.connection")
public HttpComponentsClientHttpRequestFactory customHttpRequestFactory()
{
return new HttpComponentsClientHttpRequestFactory();
}
#Bean
public RestTemplate customRestTemplate()
{
return new RestTemplate(customHttpRequestFactory());
}
}
then in your application.properties
custom.rest.connection.connection-request-timeout=...
custom.rest.connection.connect-timeout=...
custom.rest.connection.read-timeout=...
This works because HttpComponentsClientHttpRequestFactory has public setters connectionRequestTimeout, connectTimeout, and readTimeout and #ConfigurationProperties sets them for you.
For Spring 4.1 or Spring 5 without Spring Boot using #Configuration instead of XML
#Configuration
public class AppConfig
{
#Bean
public RestTemplate customRestTemplate()
{
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectionRequestTimeout(...);
httpRequestFactory.setConnectTimeout(...);
httpRequestFactory.setReadTimeout(...);
return new RestTemplate(httpRequestFactory);
}
}
I finally got this working.
I think the fact that our project had two different versions of the commons-httpclient jar wasn't helping. Once I sorted that out I found you can do two things...
In code you can put the following:
HttpComponentsClientHttpRequestFactory rf =
(HttpComponentsClientHttpRequestFactory) restTemplate.getRequestFactory();
rf.setReadTimeout(1 * 1000);
rf.setConnectTimeout(1 * 1000);
The first time this code is called it will set the timeout for the HttpComponentsClientHttpRequestFactory class used by the RestTemplate. Therefore, all subsequent calls made by RestTemplate will use the timeout settings defined above.
Or the better option is to do this:
<bean id="RestOperations" class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="readTimeout" value="${application.urlReadTimeout}" />
<property name="connectTimeout" value="${application.urlConnectionTimeout}" />
</bean>
</constructor-arg>
</bean>
Where I use the RestOperations interface in my code and get the timeout values from a properties file.
This question is the first link for a Spring Boot search, therefore, would be great to put here the solution recommended in the official documentation. Spring Boot has its own convenience bean RestTemplateBuilder:
#Bean
public RestTemplate restTemplate(
RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(500))
.setReadTimeout(Duration.ofSeconds(500))
.build();
}
Manual creation of RestTemplate instances is a potentially troublesome approach because other auto-configured beans are not being injected in manually created instances.
Here are my 2 cents. Nothing new, but some explanations, improvements and newer code.
By default, RestTemplate has infinite timeout.
There are two kinds of timeouts: connection timeout and read time out. For instance, I could connect to the server but I could not read data. The application was hanging and you have no clue what's going on.
I am going to use annotations, which these days are preferred over XML.
#Configuration
public class AppConfig {
#Bean
public RestTemplate restTemplate() {
var factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(3000);
factory.setReadTimeout(3000);
return new RestTemplate(factory);
}
}
Here we use SimpleClientHttpRequestFactory to set the connection and read time outs.
It is then passed to the constructor of RestTemplate.
#Configuration
public class AppConfig {
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofMillis(3000))
.setReadTimeout(Duration.ofMillis(3000))
.build();
}
}
In the second solution, we use the RestTemplateBuilder. Also notice the parameters of the two methods: they take Duration. The overloaded methods that take directly milliseconds are now deprecated.
Edit
Tested with Spring Boot 2.1.0 and Java 11.
Here is a really simple way to set the timeout:
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 5000;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
return clientHttpRequestFactory;
}
RestTemplate timeout with SimpleClientHttpRequestFactory
To programmatically override the timeout properties, we can customize the SimpleClientHttpRequestFactory class as below.
Override timeout with SimpleClientHttpRequestFactory
//Create resttemplate
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
//Override timeouts in request factory
private SimpleClientHttpRequestFactory getClientHttpRequestFactory()
{
SimpleClientHttpRequestFactory clientHttpRequestFactory
= new SimpleClientHttpRequestFactory();
//Connect timeout
clientHttpRequestFactory.setConnectTimeout(10_000);
//Read timeout
clientHttpRequestFactory.setReadTimeout(10_000);
return clientHttpRequestFactory;
}
RestTemplate timeout with HttpComponentsClientHttpRequestFactory
SimpleClientHttpRequestFactory helps in setting timeout but it is very limited in functionality and may not prove sufficient in realtime applications. In production code, we may want to use HttpComponentsClientHttpRequestFactory which support HTTP Client library along with resttemplate.
HTTPClient provides other useful features such as connection pool, idle connection management etc.
Read More : Spring RestTemplate + HttpClient configuration example
Override timeout with HttpComponentsClientHttpRequestFactory
//Create resttemplate
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
//Override timeouts in request factory
private SimpleClientHttpRequestFactory getClientHttpRequestFactory()
{
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
= new HttpComponentsClientHttpRequestFactory();
//Connect timeout
clientHttpRequestFactory.setConnectTimeout(10_000);
//Read timeout
clientHttpRequestFactory.setReadTimeout(10_000);
return clientHttpRequestFactory;
}
reference: Spring RestTemplate timeout configuration example
Simple timeout for restTemplate.I have set the read and write timeout for 3 seconds.
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
RestTemplate restTemplate= restTemplateBuilder.setConnectTimeout(Duration.ofMillis(3000)).setReadTimeout(Duration.ofMillis(3000)).build();
return restTemplate;
}
I had a similar scenario, but was also required to set a Proxy. The simplest way I could see to do this was to extend the SimpleClientHttpRequestFactory for the ease of setting the proxy (different proxies for non-prod vs prod). This should still work even if you don't require the proxy though. Then in my extended class I override the openConnection(URL url, Proxy proxy) method, using the same as the source, but just setting the timeouts before returning.
#Override
protected HttpURLConnection openConnection(URL url, Proxy proxy) throws IOException {
URLConnection urlConnection = proxy != null ? url.openConnection(proxy) : url.openConnection();
Assert.isInstanceOf(HttpURLConnection.class, urlConnection);
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(5000);
return (HttpURLConnection) urlConnection;
}
To expand on benscabbia's answer:
private RestTemplate restCaller = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int connectionTimeout = 5000; // milliseconds
int socketTimeout = 10000; // milliseconds
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(connectionTimeout)
.setConnectionRequestTimeout(connectionTimeout)
.setSocketTimeout(socketTimeout)
.build();
CloseableHttpClient client = HttpClientBuilder
.create()
.setDefaultRequestConfig(config)
.build();
return new HttpComponentsClientHttpRequestFactory(client);
}
private static RestTemplate restTemplate;
static {
HttpComponentsClientHttpRequestFactory rf = new HttpComponentsClientHttpRequestFactory();
rf.setReadTimeout(3 * 1000);
rf.setConnectTimeout(2 * 1000);
restTemplate = new RestTemplate(rf);
restTemplate.getMessageConverters()
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
}
Setting the timeout only in RestTemplateBuilder didn't work for me when i was using Apache's httpcomponents. I had to set the timeout in the RequestFactory as well.
Here's the entire code:
public RestTemplate templateBuilder() {
RestTemplate restTemplate = this.restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(connectTimeout))
.setReadTimeout(Duration.ofSeconds(readTimeout))
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout((int) connectTimeout * 1000);
requestFactory.setReadTimeout((int) readTimeout * 1000);
requestFactory.setConnectionRequestTimeout((int) connectTimeout * 1000);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(requestFactory));
return restTemplate;
}

Resources