本篇文章给大家带来的内容是关于springboot中配置resttemplate的方法,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
背景:最近工作上搭建了一个中间系统,采用了RestTemplate框架调用第三系统restful接口,调用方采用轮询的方式调用本系统的相关接口,期间多次出现堆内存溢出,系统假死,通用java自带的java内存分析工具分析系统生成的dump文件发现有一对象一直没被回收,占用98%堆内存,使用MAT分析该对象所在的线程,发现是使用resttemplate的相关线程,及相关的线程产生的堆对象并没有随resttemplate的close后被清除掉,网上搜索相关资料显示,传统HttpClient 在高请求量和高并发情况,很容易出现堆内存溢出的情况,而使用Apache中的HttpClient的实例CloseableHttpClient很少发生该现象,而RestTemplate默认使用的是org.springframework.http.client.ClientHttpRequest,需在配置文件进行相关的替换;
本文主要记录springboot中配置RestTemplate。
1、添加依赖:
org.apache.httpcomponents httpclient 4.5.3
系统特点: 商品多级分类检索、搜索,支持同一商品多重分类,自由设置显示式样 自由设置会员类型,自由设置权限项目,自由分配每种会员类型和每个会员的权限 灵活的商品定价,最多12级价格自由分配给各种会员类型或会员,也可针对单会员单商品特殊定价 强大的会员管理、帐户管理、订单管理功能和一系列帐务查询统计功能 灵活的会员积分系统,自由设置每个积分事件的积分计算方法 灵活的网站内容发布、管理系统,每个栏目可
2、配置CloseableHttpClient向相关属性,并设置定时清理连接
Package com.**.config;
import lombok.extern.slf4j.Slf4j;
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.comn.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.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;
/* *
* Supports both HTTP and HTTPS
* Uses a connect ion pool to re-use connect ions and save overhead of creat ing connect ions.
* Has a custom connection keep-al ive strategy (to apply a default keep-alive if one isn't specified)
* starts an idle connection monitor to cont inuously clean up stale connections.
*/
@Slf4j
@Configuration
public class HttpClientConfig {
//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) {
log.error ("Pooling Connection Manager Initialisation failure because of"+ e.getMessage(), e);
}
SSLConnectionSocketFactory sslsf = null;
try{
sslsf = new SSLConnectionSocketFactory (builder.build());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
log.error("Pooling Connection Manager Initialisation failure because of" + e.GetMessage(), e);
}
Registry socketFactoryRegistry = RegistryBuilder
.create ().register ("https", sslsf)
.register (id: "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) {
log.trace("run IdleConnectionMonitor - Closing expired and idle connections... ");
connectionManager.closeExpiredConnections();
connectionManager.closeIdleConnections(CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS, TimeUnit.SECONDS);
} else
log.info("run IdleConnectionMonitor - Http Client Connection manager is not initialised");
} catch (Exception e) {
log.error("run IdleConnectionMonitor - Exception occurred.msg={}. ", e.getMessage());
}
}
};
}
}
3、替换TestTemplate中的默认httpClient
Package com.**.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.Httpcomponentsclienthttprequestfactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;
@Slf4j
@Configuration
public class RestTemplateConfig {
@Autowired
CloseableHttpClient httpClient;
@Bean
public RestTemplate restTemplate () {
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());
/**
* StringHttpMessogeConverter 默认使用 IS0-8859-编码,此处修改为 UTF-8
*/
List> messageConverters = restTemplate.getMessageConverters();
Iterator> iterator = messageConverters.iterator();
while (iterator.hasNext()) {
HttpMessageConverter> converter = iterator.next();
if (converter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) converter).setDefaultCharset(Charset.forName("UTF-8"));
}
}
return restTemplate;
}
@Bean
public HttpComponentsClientHttpRequestFactory clientHttpRequestfactory () {
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestfactory();
clientJttpRequestFactory.setHttpClient(httpClient);
return clientHttpRequestFactory;
}
@Bean
public TaskScheduler taskScheduler() {
ThreadPooolTaskScheduler scheduler = new ThreadPooolTaskScheduler();
scheduler.setThreadNamePrefix("poolScheduler");
scheduler.setPoolSize (50);
return scheduler;
}
}
4、在启动类中注入RestTemplate类:
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}
至此,RestTemplate就可以正常使用了。









