背景:最近工作上搭建了一个中间系统,采用了RestTemplate框架调用第三系统restful接口,调用方采用轮询的方式调用本系统的相关接口,期间多次出现堆内存溢出,系统假死,通用java自带的java内存分析工具分析系统生成的dump文件发现有一对象一直没被回收,占用98%堆内存,使用MAT分析该对象所在的线程,发现是使用resttemplate的相关线程,及相关的线程产生的堆对象并没有随resttemplate的close后被清除掉,网上搜索相关资料显示,传统HttpClient 在高请求量和高并发情况,很容易出现堆内存溢出的情况,而使用Apache中的HttpClient的实例CloseableHttpClient很少发生该现象,而RestTemplate默认使用的是org.springframework.http.client.ClientHttpRequest,需在配置文件进行相关的替换;

本文主要记录springboot中配置RestTemplate。

1、添加依赖:

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>

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 <ConnectionSocketFactory> 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、替换RestTemplate中的默认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<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
Iterator<HttpMessageConverter<?>> 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() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("poolScheduler");
scheduler.setPoolSize (50);
return scheduler;
}
}

4、在启动类中注入RestTemplate类:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}

至此,RestTemplate就可以正常使用了。

参考资料:https://www.cnblogs.com/jimw/p/9037542.html

SpingBoot —— RestTemplate的配置的更多相关文章

  1. RestTemplate

    RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率.调用RestTemplate的 ...

  2. 使用RestTemplate访问restful服务时遇到的问题

    可以通过通过wireshark抓包,使用Postman发送请求 wireshark是非常流行的网络封包分析软件,功能十分强大.可以截取各种网络封包,显示网络封包的详细信息.使用wireshark的人必 ...

  3. RestTemplate 微信接口 text/plain HttpMessageConverter

    一.背景介绍 使用 Spring Boot 写项目,需要用到微信接口获取用户信息. 在 Jessey 和 Spring RestTemplate 两个 Rest 客户端中,想到尽量不引入更多的东西,然 ...

  4. 如何使用RestTemplate访问restful服务

    一. 什么是RestTemplate 传统情况下在java代码里访问restful服务,一般使用Apache的HttpClient.不过此种方法使用起来太过繁琐.spring提供了一种简单便捷的模板类 ...

  5. springcloud配置需要主要的地方

    Eureka服务端 注册中心 <!-- Eureka服务端 --> <dependency> <groupId>org.springframework.cloud& ...

  6. Springboot 使用 RestTemplate

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code spring web 项目提供的RestTemplate,使java访问url更方便, ...

  7. (转载)spring RestTemplate用法详解

    前面介绍过spring的MVC结合不同的view显示不同的数据,如:结合json的view显示json.结合xml的view显示xml文档.那么这些数据除了在WebBrowser中用JavaScrip ...

  8. spring的RestTemplate使用指南

    前言:现在restful接口越来越广泛,而如今很多接口摒弃了传统的配置复杂的webService开发模式,在java领域只需要很简单的springMvc就可以声明为一个控制器,再加上service层, ...

  9. 使用RestTemplate时报错java.lang.IllegalStateException: No instances available for 127.0.0.1

    我在RestTemplate的配置类里使用了 @LoadBalanced@Componentpublic class RestTemplateConfig { @Bean @LoadBalanced ...

随机推荐

  1. Python文件读写及网站显示

    一.关于文件读写的笔记 (一) 文件概述 文件是一个存储在辅助存储器上的数据序列,可以包含任何数据内容 文件都是按照2进制进行存储的,但在表现形式上有2种:文本文件和二进制文件. 1. 文本文件 文本 ...

  2. libffi-dev : 依赖: libffi6 (= 3.2.1-4) 但是 3.2.1-4kord 正要被安装

    原文链接:https://blog.csdn.net/u013992330/article/details/85135629 中标麒麟安装python库:sshtunnel 的时候提示缺少ffi.h文 ...

  3. Centos7调整swap分区

    如何让服务器响应更快?如何避免应用出现内存不足的错误?最简单的方法就是增加交换空间.Swap是存储盘上的一块自留地,操作系统可以在这里暂存一些内存里放不下的东西. 这从某种程度上相当于增加了服务器的可 ...

  4. redis缓存存在的隐患及其解决方案

    redis缓存1.缓存穿透 1>.什么是缓存穿透? 业务系统需要查训的数据根本不存在,当业务系统查询时, 首先会在缓存中查训,由于缓存中不存在,然后在往数据 库中查,由于该数据在数据库中也不存在 ...

  5. 腾讯开源极限渲染js模板链接

    https://aui.github.io/art-template/zh-cn/index.html

  6. django基础之一

    Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...

  7. Python-doc rst文件打开

    Python rst文件打开 RST与Python类似Javadoc与Java. 如果下载了别人的Python源码,里面有rst文件夹,我们可以转为html后用浏览器打开 某个开源项目的index.r ...

  8. VS2015 WPF Prism Xaml Designer error

    Ref: http://wiki.tk2kpdn.com/build-error-prism5-interactionrequesttrigger-with-vs2015/ gacutil -i &q ...

  9. MVC3学习:实现简单的相册管理和图片管理

    相册管理说白了就是文件夹管理,因此要用到命名空间using System.IO; 一.先来做相册管理,添加相册我就不做了,就是添加文件夹,这里主要做一下相册的显示.相册在页面上显示,需要一张图片,可以 ...

  10. C# 多线程学习系列二

    一.关于前台线程和后台线程 1.简介 CLR中线程分为两种类型,一种是前台线程.另一种是后台线程. 前台线程:应用程序的主线程.Thread构造的线程都默认为前台线程 后台线程:线程池线程都为后台线程 ...