HowToDoInJava

  • Python
  • Java
  • Spring Boot
  • Dark Mode
Home / Spring REST / Configuring Spring RestTemplate with HttpClient

Configuring Spring RestTemplate with HttpClient

In Spring RestTemplate example, we learned to access REST APIs inside Spring application. In this tutorial, we are extending the RestTemplate 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.

1. HttpClient Configuration

In HttpClientConfig class, we are configuring mainly two things –

  1. PoolingHttpClientConnectionManager – 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 helps in setting time which decide how long a connection can remain idle before being reused.

  2. 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 bean. It is what RestTemplate will use to get the connection to API endpoints.

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

2. Spring 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, which is used to create RestTemplate.

  1. HttpComponentsClientHttpRequestFactory is ClientHttpRequestFactory implementation that uses Apache HttpComponents HttpClient to create requests.
  2. We have used @Scheduled annotation in httpClient configuration. To support this, we have to add support of scheduled execution of thread. For that, we have used bean ThreadPoolTaskScheduler which internally utilizes ScheduledThreadPoolExecutor to schedule commands to run after a given delay, or to execute periodically.
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;
	}
}

3. How to use Spring RestTemplate

To use above configured RestTemplate, simply inject it to controller or test class.

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

		String result = restTemplate.getForObject(uri, String.class);

		Assert.assertEquals(true, result.indexOf("Lokesh") > 0);
	}
}

4. 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:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 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</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>
Download Sourcecode

Happy Learning !!

References:

HttpClient Docs
Spring RestTemplate Java Doc

Was this post helpful?

Let us know if you liked the post. That’s the only way we can improve.

Share this:

  • Twitter
  • Facebook
  • LinkedIn
  • Reddit

About Lokesh Gupta

A family guy with fun loving nature. Love computers, programming and solving everyday problems. Find me on Facebook and Twitter.

Feedback, Discussion and Comments

  1. bing

    July 23, 2020

    How to shut down the taskScheduler?

  2. Fholisani

    June 21, 2020

    How would you externalize the value for fixedDelay. @Scheduled(fixedDelay = 10000) ?

    Since it requires compile time constant… does spring have alternative schedules that will pass the value from external config at run time ?

    Thanks for the tutorial.

  3. aravind

    June 16, 2020

    is there way log the total number of connection , number of connection used , number of connection ideal..

  4. Aman Bansal

    April 1, 2020

    When i configured same i got 404 while calling https and working for http. Could you please help me on that

  5. Otmane

    July 5, 2019

    Greate article.
    I used it to configure WebServiceTempate for SOAP WS.
    It worked like a charm.

    Thanks

    • Harsh Biyani

      August 27, 2019

      Could you please share the template.

  6. Ranjith Viswanathan

    June 14, 2019

    Connection Keep alive is not needed if we are ok with PoolingConnectionManager’s 2000 ms default stale connections. Its explained in below link as default 2000ms and we can modify via constructor of PoolingConnManager

    https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html#PoolingHttpClientConnectionManager(long,%20java.util.concurrent.TimeUnit)

  7. Bala Kajendran

    April 8, 2019

    Please kindly post how to consume https rest service using spring 3.0

  8. Bhargav

    December 21, 2018

    Hi Lokesh,

    Wen i configured same i got 404 while calling https rest call but when i post using postman the same url its working. I dont know the reason ?

    • Aman Bansal

      April 1, 2020

      same for me ..

Comments are closed on this article!

Search Tutorials

Spring Boot RestTemplate

  • RestTemplate Introduction
  • RestTemplate Builder
  • RestTemplate with HttpClient
  • RestTemplate GET Example
  • RestTemplate POST Example
  • RestTemplate Basic Auth
  • RestTemplate Timeout
  • ClientHttpRequestInterceptor

Spring Boot 2 Tutorial

  • Spring Boot – Introduction
  • Spring Boot – Starter parent
  • Spring Boot – Starter templates
  • Spring Boot – Multi-module project
  • Spring Boot – Annotations
  • Spring Boot – Auto configuration
  • Spring Boot – AOP
  • Spring Boot – Logging
  • Spring Boot – DevTools
  • Spring Boot – WAR Packaging
  • Spring Boot – REST API
  • Spring Boot – CRUD
  • Spring Boot – OAuth2
  • Spring Boot – Testing
  • Spring Boot – RestTemplate
  • Spring Boot – Thymeleaf
  • Spring Boot – Hibernate
  • Spring Boot – DataSource
  • Spring Boot – Error Handling
  • Spring Boot – Caching
  • Spring Boot – Retry
  • Spring Boot – BasicAuth
  • Spring Boot – H2 Database
  • Spring Boot – Ehcache 3.x
  • Spring Boot – Gson
  • Spring Boot – RMI
  • Spring Boot – Send Email
  • Spring Boot – Interview Questions

Spring Boot Tutorial

  • Spring Boot – CommandLineRunner
  • Spring Boot – Configure Jetty
  • Spring Boot – Tomcat Default Port
  • Spring Boot – Context Root
  • Spring Boot – SSL [https]
  • Spring Boot – Get all loaded beans
  • Spring Boot – PropertyEditor
  • Spring Boot – @EnableScheduling
  • Spring Boot – Jersey
  • Spring Boot – SOAP Webservice
  • Spring Boot – SOAP Client
  • Spring Boot – JMSTemplate
  • Spring Boot – REST APIs
  • Spring Boot – JSP View
  • Spring Boot – Actuator endpoints
  • Spring Boot – Role Based Security
  • Spring Boot – RSS / ATOM Feed
  • Spring Boot – Ehcache 2.x

Meta Links

  • About Me
  • Contact Us
  • Privacy policy
  • Advertise
  • Guest and Sponsored Posts

Recommended Reading

  • 10 Life Lessons
  • Secure Hash Algorithms
  • How Web Servers work?
  • How Java I/O Works Internally?
  • Best Way to Learn Java
  • Java Best Practices Guide
  • Microservices Tutorial
  • REST API Tutorial
  • How to Start New Blog

Copyright © 2020 · HowToDoInjava.com · All Rights Reserved. | Sitemap

  • Java 15 New Features
  • Sealed Classes and Interfaces
  • EdDSA (Ed25519 / Ed448)