
Let’s say you are invoking a REST service using Spring’s REST template.
And you want to set the read time out to a certain value. You don’t want the invoked service to take too much time to send data.
You can do this in two ways:
- Set the time out locally
- Set the time out at the application level
Setting the read time out locally:
Let’s assume you are calling a GET service deployed at localhost:8080 which just returns a string message.
To invoke this using Spring REST template you can do this :
RestTemplate template = new RestTemplate();
String response = template.getForObject("http://localhost:8080/getData",String.class);
The variable response will have the value returned by the GET service.
If you want to wait only for half a second before the GET service returns data , you can set the read time out using SimpleClientRequestFactory like this:
RestTemplate template = new RestTemplate();
SimpleClientHttpRequestFactory rf =
(SimpleClientHttpRequestFactory)template.getRequestFactory();
rf.setReadTimeout(500);
String response = template.getForObject("http://localhost:8080/getData",String.class);
An instance of SimpleClientHttpRequestFactory is obtained from the rest template instance. And the time out value is set on it.
That’s it. Now if the GET service takes more than half a second to return data the service throws an exception like this :
java.net.SocketTimeoutException: Read timed out
at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283) ~[na:na]
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309) ~[na:na]
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350) ~[na:na]
at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803) ~[na:na]
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:982) ~[na:na]
Notice that read time out is different from connection time out . Connection time is the time taken to establish connection with the consumed REST service .Read time is the time taken to read the data returned by the REST service.
Setting the read time out at the application level:
If you want the above read time out configuration for all of the REST services consumed by the application you can add a configuration file and create a custom REST Template inside the file like this:
package com.resttemplate.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestConfig {
@Bean
public RestTemplate myRestTemplate(){
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout(500);
return new RestTemplate(requestFactory);
}
}
The above configuration creates a customized Spring Bean (RestTemplate bean).
To use this bean, autowire it in the class where you are consuming the third party REST service.
package com.resttemplate.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
public class RestClient {
@Autowired
private RestTemplate restTemplate;
public String getDataFromService() {
String response = restTemplate.getForObject("http://localhost:8080/getData", String.class);
return response;
}
}
If you invoke the service now and it again takes more than half a second to return data , the same read time out exception is thrown.
Connection time out can be set out the same way as read time out using setConnectTimeOut() method of SimpleClientRequestFactory class.
This design approach followed by Spring is less intuitive though. Why not add a method setReadTimeOut() on the class RestTemplate itself? Why does the developer need to know about SimpleClientRequestFactory? .
Leave a Reply