setting timeout using #ConfigurationProperties in SpringBoot - spring-boot

I am going through a code that configures dedicated restTemplate for a rest operation. I see the following properties
httpProperties.connection-request-timeout=6100
httpProperties.connect-timeout=6100
httpProperties.read-timeout=6100
My Config class looks like below
#Bean
#ConfigurationProperties(prefix = "httpProperties")
public HttpComponentsClientHttpRequestFactory webSystemHttpRequestFactory() {
SSLContext sslContext;
try {
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom().setMaxConnTotal(maxTotalConnection)
.setMaxConnPerRoute(maxConnectionPerRoute).setSSLSocketFactory(socketFactory).build();
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
catch(Exception e) {
}
return new HttpComponentsClientHttpRequestFactory();
}
#Bean(name = "webSystemRestTemplate")
public RestTemplate webSystemRestTemplate() {
RestTemplate restTemplate = new RestTemplate(webSystemHttpRequestFactory());
return restTemplate;
}
I can see the logs
o.a.h.i.c.DefaultManagedHttpClientConnection.setSocketTimeout - http-outgoing-1: set socket timeout to 6100
Here is what i want to understand:
How is this value set and to which property by the #CnfigurationProperties annotation?
Is it applicable at the spring boot application level or at each request level?
Please help me understand the concept underlying.
Note: Apache http client version used is 4.5.2

In the source code for HttpComponentsClientHttpRequestFactory.class there is an object called RequestConfig.class.
In it's source code you can see that there are three parameters.
private final Timeout connectionRequestTimeout;
private final Timeout connectTimeout;
private final Timeout responseTimeout;
These are the ones that the parameters map to using
#ConfigurationProperties(prefix = "httpProperties")
That is not the most common way to set these parameters. But there are multiple ways to set these as pointed out here.
RestTemplate timeout examples

The properties are setting the attributes connectionRequestTimeOut, connectTimeOut and readTimeOut of the HttpComponentsClientHttpRequestFactory class. The mapping is done using the ConfigurationProperties annotation that maps the kebab case property names to the bean attributes.
HttpComponentsClientHttpRequestFactory documentation :
HttpComponentsClientHttpRequestFactory

Related

Adding Java environment variables in application.properties in springboot

I am running a springboot application which requires to trust the certificate which i added in my local truststore.
For now i am setting it under run configurations options in intellij and it works.
ex->::-Djavax.net.ssl.trustStore=location\cacerts;-Djavax.net.ssl.trustStorePassword=changeit
I was wondering is there any way to set it from application.properties file in springboot in the way we set spring properties?
If you want to make REST calls, You can configure the RestTemplate Bean like :
#Configuration
public class SslConfiguration {
#Value("${http.client.ssl.trust-store}")
private Resource keyStore;
#Value("${http.client.ssl.trust-store-password}")
private String keyStorePassword;
#Bean
RestTemplate restTemplate() throws Exception {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(
keyStore.getURL(),
keyStorePassword.toCharArray()
).build();
SSLConnectionSocketFactory socketFactory =
new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory).build();
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
}
Check this : Example

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;
}

How to set custom Jackson ObjectMapper with Spring Cloud Netflix Feign

I'm running into a scenario where I need to define a one-off #FeignClient for a third party API. In this client I'd like to use a custom Jackson ObjectMapper that differs from my #Primary one. I know it is possible to override spring's feign configuration defaults however it is not clear to me how to simply override the ObjectMapper just by this specific client.
Per the documentation, you can provide a custom decoder for your Feign client as shown below.
Feign Client Interface:
#FeignClient(value = "foo", configuration = FooClientConfig.class)
public interface FooClient{
//Your mappings
}
Feign Client Custom Configuration:
#Configuration
public class FooClientConfig {
#Bean
public Decoder feignDecoder() {
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
ObjectFactory<HttpMessageConverters> objectFactory = () -> httpMessageConverters;
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
public ObjectMapper customObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
//Customize as much as you want
return objectMapper;
}
}
follow #NewBie`s answer, i can give the better one...
#Bean
public Decoder feignDecoder() {
return new JacksonDecoder();
}
if you want use jackson message converter in feign client, please use JacksonDecoder, because SpringDecoder will increase average latency of feignclient call in production.
<!-- feign-jackson decoder -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>10.1.0</version>
</dependency>
Define a custom decoder as below, annotated with #Configuration and set as parameter for the feign client interface, configuration = CustomFeignClientConfig.class
#Configuration
public class CustomFeignClientConfig {
#Bean
public Decoder feignDecoder() {
return (response, type) -> {
String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));
JavaType javaType = TypeFactory.defaultInstance().constructType(type);
return new ObjectMapper().readValue( bodyStr, javaType);
};
}
}
#NewBie's answer has serious performance problems. During the new HttpMessageConverters process, loadclass will be performed, resulting in a large number of thread block. If you have used this code, please modify it as follows:
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
change to
HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
ObjectFactory<HttpMessageConverters> objectFactory = () -> httpMessageConverters;
You can use JMeter and Arthas to reproduce this phenomenon, and the modified program has been greatly improved.

Spring configurable, high performance, metered http client instances

Coming from DropWizard I am used to its HttpClientConfiguration and I am baffled that in Spring Boot I cannot find some support for controlling in a similar manner http clients instances to be used, by RestTemplates for example.
To work in production the underlying client implementation should be high performance (e.g. non blocking io, with connection reuse and pooling).
Then I need to set timeouts or authentication, possibly metrics gathering, cookie settings, SSL certificates settings.
All of the above should be easy to set up in different variants for different instances to be used in different contexts (e.g. for service X use these settings and this pool, for Y use another pool and settings) and most parameters should be set via environment-specific properties to have different values in production/qa/development.
Is there something that can be used towards this end?
Below is an example of configuring a HttpClient with a configuration class. It configures basic authentication for all requests through this RestTemplate as well as some tweaks to the pool.
HttpClientConfiguration.java
#Configuration
public class HttpClientConfiguration {
private static final Logger log = LoggerFactory.getLogger(HttpClientConfiguration.class);
#Autowired
private Environment environment;
#Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
restTemplate.setInterceptors(ImmutableList.of((request, body, execution) -> {
byte[] token = Base64.encodeBase64((format("%s:%s", environment.getProperty("fake.username"), environment.getProperty("fake.password"))).getBytes());
request.getHeaders().add("Authorization", format("Basic %s", new String(token)));
return execution.execute(request, body);
}));
return restTemplate;
}
#Bean
public HttpClient httpClient() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
// Get the poolMaxTotal value from our application[-?].yml or default to 10 if not explicitly set
connectionManager.setMaxTotal(environment.getProperty("poolMaxTotal", Integer.class, 10));
return HttpClientBuilder
.create()
.setConnectionManager(connectionManager)
.build();
}
/**
* Just for demonstration
*/
#PostConstruct
public void debug() {
log.info("Pool max total: {}", environment.getProperty("poolMaxTotal", Integer.class));
}
}
and an example application.yml
fake.username: test
fake.password: test
poolMaxTotal: 10
You can externalise configuration values to your application.yml as with poolMaxTotal etc. above.
To support different values per environment you can use Spring profiles. Using the example above, you could just create application-prod.yml with a "prod" specific value for poolMaxTotal. Then start your app with --spring.profiles.active=prod and the "prod" value will be used instead of your default value in application.yml. You can do this for however many environments you need.
application-prod.yml
poolMaxTotal: 20
For an async HttpClient, see here: http://vincentdevillers.blogspot.fr/2013/10/a-best-spring-asyncresttemplate.html

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