美文网首页JAVA技术文章
https://howtodoinjava.com/spring

https://howtodoinjava.com/spring

作者: rejoice001 | 来源:发表于2018-05-11 16:07 被阅读95次

FROM: https://howtodoinjava.com/spring/spring-restful/resttemplate-httpclient-java-config/

<header class="entry-header" style="box-sizing: border-box; display: block; color: rgb(68, 68, 68); font-family: "Open Sans", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">

RestTemplate with HttpClient – Java Configuration Example

<time class="entry-time" itemprop="datePublished" datetime="2018-04-21T17:54:05+00:00" style="box-sizing: border-box;">April 21, 2018</time> by Lokesh Gupta

</header>

We have already gone through the RestTemplate examples for accessing REST APIs inside spring application. In this example, we are extending the 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.

HttpClient Configuration

In HttpClientConfig class, we are configuring mainly two things –

  1. [PoolingHttpClientConnectionManager](https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html) – 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](https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/ConnectionKeepAliveStrategy.html) 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](https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/CloseableHttpClient.html) bean. It is what RestTemplate will use to get the connection to API endpoints.

<caption style="box-sizing: border-box; padding-top: 8px; padding-bottom: 8px; color: rgb(119, 119, 119); text-align: left;">HttpClientConfig.java</caption>
|

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

}

}

};

}

}

|

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](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/ClientHttpRequestFactory.html), which is used to create RestTemplate.

  1. [HttpComponentsClientHttpRequestFactory](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.html) 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.

<caption style="box-sizing: border-box; padding-top: 8px; padding-bottom: 8px; color: rgb(119, 119, 119); text-align: left;">RestTemplateConfig.java</caption>
|

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;

}

}

|

How to use RestTemplate

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

<caption style="box-sizing: border-box; padding-top: 8px; padding-bottom: 8px; color: rgb(119, 119, 119); text-align: left;">TestApplication.java</caption>
|

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](http://localhost:8080/employees)"``;

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

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

}

}

|

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:

<caption style="box-sizing: border-box; padding-top: 8px; padding-bottom: 8px; color: rgb(119, 119, 119); text-align: left;">pom.xml</caption>
|

<``project xmlns``=``"[http://maven.apache.org/POM/4.0.0](http://maven.apache.org/POM/4.0.0)"``xmlns:xsi``=``"[http://www.w3.org/2001/XMLSchema-instance](http://www.w3.org/2001/XMLSchema-instance)"

xsi:schemaLocation``=``"[http://maven.apache.org/POM/4.0.0](http://maven.apache.org/POM/4.0.0)[http://maven.apache.org/xsd/maven-4.0.0.xsd](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](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

References:

HttpClient Docs
Spring RestTemplate class

关注我的博客:http://www.rejoiceblog.com/

相关文章

网友评论

本文标题:https://howtodoinjava.com/spring

本文链接:https://www.haomeiwen.com/subject/lagfdftx.html