高并发下RestTemplate的正确使用

如果java项目里有调用第三方的http接口,我们可以使用RestTemplate去远程访问。也支持配置连接超时和响应超时,还可以配置各种长连接策略,也可以支持长连接预热,在高并发下,合理的配置使用能够有效提高第三方接口响应时间。

一、RestTemplate是什么?

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

二、如何使用

1.创建一个bean

以下代码配置比较简单,只设置了连接超时时间和响应超时时间

* restTemplate配置 * @author Songsong * @date 2020-08-17 15:09 @Configuration public class RestTemplateConfiguration { @Bean ( name = "restTemplate" ) public RestTemplate restTemplate ( ) { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory ( ) ; //设置连接超时时间1s factory . setConnectTimeout ( 1000 ) ; //设置读取时间1s factory . setReadTimeout ( 1000 ) ; return new RestTemplate ( factory ) ;

2.使用步骤

在需要使用的地方使用@Resource或者@Autowired注入进来

@Resource
private RestTemplate restTemplate;

然后我们平常调用第三方的接口是get方式和post方式,restTemplate提供getForEntity和postForEntity方法支持这两种方式,直接调用即可,源码分别如下:

getForEntity方法:

 public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = this.acceptHeaderRequestCallback(responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
        return (ResponseEntity)nonNull(this.execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));

postForEntity方法:

public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = this.httpEntityCallback(request, responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
        return (ResponseEntity)nonNull(this.execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));

源码中还有很多以上两种其他的重载方法,以上是作者平常项目中用的最多的一种,参数有url(第三方http链接)、request是请求所需的参数,responseType是返回类型里的泛型。
只需要解析返回的参数即可。

三、高并发下的RestTemplate使用

在平常的开发中,以上简单的配置可能就够用了,但是在高并发下,对接口响应时间要求很高,所以我们需要尽量的提高第三方接口响应时间。在RestTemplate中可以使用httpClient长连接,关于httpClient长连接的介绍我们可以参考:HTTPclient保持长连接
以下代码我们设置了长连接预热的功能,以及路由并发数:

@Slf4j
@Configuration
public class RestTemplateConfiguration {
    @Bean(name = "restTemplate")
    public RestTemplate restTemplate() {
       return getRestTemplate(3, "https://www.baidu.com/......");
    private RestTemplate getRestTemplate(int maxTotal, String preHeatUrl) {
        HttpComponentsClientHttpRequestFactory httpRequestFactory = httpComponentsClientHttpRequestFactory(maxTotal);
        RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
        //解决首次预热耗时长
        if (StringUtils.isNotEmpty(preHeatUrl)) {
            try {
                restTemplate.postForEntity(preHeatUrl, "", String.class);
            } catch (Exception e) {
                log.error("preHeat url error:{}", e.getMessage());
        return restTemplate;
     * ClientHttpRequestFactory接口的另一种实现方式(推荐使用),即:
     * HttpComponentsClientHttpRequestFactory:底层使用Httpclient连接池的方式创建Http连接请求
     * @return
    private HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(int maxTotal) {
        //Httpclient连接池,长连接保持时间
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(1, TimeUnit.HOURS);
        //设置总连接数
        connectionManager.setMaxTotal(maxTotal);
        //设置同路由的并发数
        connectionManager.setDefaultMaxPerRoute(maxTotal);
        //设置header
        List<Header> headers = new ArrayList<Header>();
        headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04"));
        headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate"));
        headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"));
        headers.add(new BasicHeader("Connection", "keep-alive"));
        //创建HttpClient
        HttpClient httpClient = HttpClientBuilder.create()
                .setConnectionManager(connectionManager)
                .setDefaultHeaders(headers)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) //设置重试次数
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) //设置保持长连接
                .build();
        //创建HttpComponentsClientHttpRequestFactory实例
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory(httpClient);
        //设置客户端和服务端建立连接的超时时间
        requestFactory.setConnectTimeout(10000);
        //设置客户端从服务端读取数据的超时时间
        requestFactory.setReadTimeout(5000);
        //设置从连接池获取连接的超时时间,不宜过长
        requestFactory.setConnectionRequestTimeout(2000);
        //缓冲请求数据,默认为true。通过POST或者PUT大量发送数据时,建议将此更改为false,以免耗尽内存
        requestFactory.setBufferRequestBody(false);
        return requestFactory;

(1)设置预热功能
我们可以看到,在getRestTemplate方法中,

return restTemplate;

之前先请求了一次,也就是说在需要使用第三方接口调用的service层注入的时候,提前先调用了一次,根据长连接的特性,一般第一次连接的时间较长,使用完之后,这个连接并不会马上回收掉,在一定的时间还是存活状态,所以在高并发下,经过预热后的接口响应时间会大幅提高。

(2)合理设置maxtotal数量
我们可以看到以下代码

//设置总连接数
 connectionManager.setMaxTotal(maxTotal);

我们可以看到这一行,maxTotal是设置总连接数,这个设置需要根据接口的响应时间以及需要支持的QPS来设置,比如接口响应时间是100ms,需要支持的QPS为5000,也就是5000/s,那么一个长连接1s就是能够处理10个请求,那么总共需要maxTotal为500个,这个就是设置的大概数量,但是有时候QPS不是那么稳定,所以具体设置多少得视具体情况而定。

RestTemplate深度解析可以参考: RestTemplate深度解析

以上就是关于RestTemplate的使用介绍,其实平常使用下还好,看不出来什么问题,但是一旦高并发情况下,预热和设置总连接数还有并发数以及其他的相关配置就显得尤为重要,具体的配置还是得经过实验才能得知,没有最好,只有更好,以上就是作者在高并发活动中的一些实际经历,希望可以帮助到你!!!

HttpClient、OKhttp、RestTemplate接口调用对比 HttpClient、OkHttp 和 RestTemplate 是三种常用的 Java HTTP 客户端库,它们都可以用于发送 HTTP 请求和接收 HTTP 响应,但在一些方面有所不同。下面是它们之间的一些对比: HttpClient: Apache HttpClient: ○ 成熟稳定: Apache HttpClient 是 Apache 软件基金会的一个项目,经过多年的发展,已经非常成熟和稳定。 ○ 灵活性: 提供了丰富的
import com.gitee.taven.ApiResult; import com.gitee.taven.aop.RepeatSubmitAspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframew.
一. 什么是RestTemplate 传统情况下在java代码里访问restful服务,一般使用Apache的HttpClient。不过此种方法使用起来太过繁琐。spring提供了一种简单便捷的模板类来进行操作,这就是RestTemplate。 二.一个简单的例子。 定义一个简单的restful接口 2、为什么使用apache的构建器? 因为简单粗暴,使用方式比较直接,当然,也可以手写一个 3、对于spring cloud项目来说,替换一个具有连接池功能的RestTemplate可以提升feign的性能,具体原因参考第一点 import org.apache.http.client.config.RequestConfig; import org.apache.h
rsp = new RestTemplate(); // headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8")); //调用代码段
1.JavaGuide Guide 哥大三开始维护的,目前算是纯 Java 类型项目中 Star 数量最多的项目了。但是,本仓库的价值远远(+N次 )比不上像 Spring Boot、Elasticsearch 等等这样非常非常非常优秀的项目。希望以后我也有能力为这些项目贡献一些有价值的代码。 Github 地址:github.com/Snailclimb/… Star: 66.3k 介绍: 【Java 学习+面试指南】 一份涵盖大部分 Java 程序员所需要掌握的核心知识。 2.java-desi
1、List(有序、可重复) List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。 2、Set(无序、不能重复) Set里存放的对象是无序,不能重复的,集合中的对象.
Java面向对象有哪些特征,如何应用 ​ 面向对象编程是利用类和对象编程的一种思想。万物可归类,类是对于世界事物的高度抽象 ,不同的事物之间有不同的关系 ,一个类自身与外界的封装关系,一个父类和子类的继承关系, 一个类和多个类的多态关系。万物皆对象,对象是具体的世界事物,面向对象的三大特征封装,继承,多态。封装,封装说明一个类行为和属性与其他类的关系,低耦合,高内聚;继承是父类和子类的关系,多态说的是类与类的关系。 ​ 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数
1.JavaGuide Guide 哥大三开始维护的,目前算是纯 Java 类型项目中 Star 数量最多的项目了。但是,本仓库的价值远远(+N次 )比不上像 Spring Boot、Elasticsearch 等等这样非常非常非常优秀的项目。希望以后我也有能力为这些项目贡献一些有价值的代码。 Github 地址:github.com/Snailclimb/… Star: 66.3k 介绍: 【J...
使用RestTemplate post请求的时候主要可以通过三种方式实现 1、调用postForObject方法2、使用postForEntity方法 3、调用exchange方法 postForObject和postForEntity方法的区别主要在于可以在postForEntity方法中设置header的属性,当需要指定header的属性值的时候,使用postForEntity方法。exchange方法和postForEntity类似,但是更灵活,exchange还可以调用get...
RestTemplateSpring框架提供的用于发送HTTP请求的客户端工具。它可以用于调用第三方的HTTP接口,并支持配置连接超时和响应超时,以及各种长连接策略和长连接预热。在高并发场景下,合理配置和使用RestTemplate可以有效提高第三方接口的响应时间。 以下是使用RestTemplate进行高并发的一般步骤: 1. 创建一个RestTemplate实例: ```java RestTemplate restTemplate = new RestTemplate(); 2. 配置连接超时和响应超时: ```java restTemplate.setRequestFactory(new SimpleClientHttpRequestFactory()); restTemplate.getRequestFactory().setConnectTimeout(5000); // 连接超时时间为5秒 restTemplate.getRequestFactory().setReadTimeout(5000); // 响应超时时间为5秒 3. 发送HTTP请求: ```java String url = "http://example.com/api"; ResponseEntity<String> response = restTemplate.getForEntity(url, String.class); String responseBody = response.getBody(); 4. 处理响应结果: ```java if (response.getStatusCode() == HttpStatus.OK) { // 处理成功响应 // ... } else { // 处理错误响应 // ... 需要注意的是,在高并发场景下,还需要考虑连接池的配置和使用,以及合理的线程池配置等。