RestTemplate使用长连接

2024-08-28 02:12
文章标签 使用 连接 resttemplate

本文主要是介绍RestTemplate使用长连接,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 1. HTTP协议的长连接和短连接
      • 2. RestTemplate的长连接和短连接
        • 2.1 RestTemplate的构造方法:
        • 2.2 验证RestTemplate的默认请求工厂:
        • 2.3 验证SimpleClientHttpRequestFactory每次请求开启新连接:
      • 3. RestTemplate使用长连接

1. HTTP协议的长连接和短连接

HTTP协议的长连接和短连接,本质上是TCP协议的长连接和短连接。

长连接(持久连接)和短连接(非持久连接)的区别在于:
长连接:连接建立后,保持打开状态,可以复用同一连接进行多个请求和响应。减少了频繁的连接建立和断开开销,适用于需要频繁通信的场景,如 HTTP/1.1 和 WebSocket。
短连接:每次请求后,连接都会关闭。每次新的请求都需要重新建立连接,适用于通信频率较低的场景,如 HTTP/1.0。

在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。

从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入:Connection:keep-alive。在使用长连接的情况下,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件中设定这个时间。

2. RestTemplate的长连接和短连接

2.1 RestTemplate的构造方法:

RestTemplate的构造方法:
RestTemplate()
RestTemplate(ClientHttpRequestFactory requestFactory)
RestTemplate(List<HttpMessageConverter<?>> messageConverters)

ClientHttpRequestFactory接口的实现很多,其中最常用的有以下两种:
SimpleClientHttpRequestFactory(封装URLConnection)
HttpComponentsClientHttpRequestFactory(封装HttpClient)

RestTemplate默认使用短连接,也就是每次发送请求都会建立一个新的TCP连接。这是因为RestTemplate的默认请求工厂是SimpleClientHttpRequestFactory,它没有连接池的概念。

如果需要使用长连接,可以使用HttpComponentsClientHttpRequestFactory,它支持连接池,并且可以通过setMaxTotal()和setDefaultMaxPerRoute()方法设置最大连接数和每个路由的最大连接数。

另外,需要注意的是,长连接并不是在所有情况下都能带来性能提升。在高并发场景下,使用长连接可能会导致连接池中的连接被占满,从而导致新的请求被阻塞。因此,在选择使用长连接时,需要根据实际情况进行评估和测试,以确定最合适的连接方式。

2.2 验证RestTemplate的默认请求工厂:

RestTemplate restTemplate = new RestTemplate();
System.out.println(restTemplate.getRequestFactory());

打印结果:
org.springframework.http.client.SimpleClientHttpRequestFactory@5d740a0f

代码追踪:
在RestTemplate的默认构造方法中并没有显示指明为SimpleClientHttpRequestFactory。

public RestTemplate() {this.messageConverters = new ArrayList();this.errorHandler = new DefaultResponseErrorHandler();this.headersExtractor = new RestTemplate.HeadersExtractor();this.messageConverters.add(new ByteArrayHttpMessageConverter());this.messageConverters.add(new StringHttpMessageConverter());this.messageConverters.add(new ResourceHttpMessageConverter(false));try {this.messageConverters.add(new SourceHttpMessageConverter());} catch (Error var2) {}this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());if (romePresent) {this.messageConverters.add(new AtomFeedHttpMessageConverter());this.messageConverters.add(new RssChannelHttpMessageConverter());}if (jackson2XmlPresent) {this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());} else if (jaxb2Present) {this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());}if (jackson2Present) {this.messageConverters.add(new MappingJackson2HttpMessageConverter());} else if (gsonPresent) {this.messageConverters.add(new GsonHttpMessageConverter());} else if (jsonbPresent) {this.messageConverters.add(new JsonbHttpMessageConverter());}if (jackson2SmilePresent) {this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());}if (jackson2CborPresent) {this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());}this.uriTemplateHandler = initUriTemplateHandler();}

发现:RestTemplate extends InterceptingHttpAccessor implements RestOperations
然后查看InterceptingHttpAccessor ,发现:InterceptingHttpAccessor extends HttpAccessor
然后查看HttpAccessor,发现定义了成员变量private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
所以从代码角度验证了默认请求工厂为SimpleClientHttpRequestFactory。
不知道怎么追踪源码的时候,可以打上断点,然后一步一步深入到方法里面,然后去看变量是哪一步被赋值的。

2.3 验证SimpleClientHttpRequestFactory每次请求开启新连接:

示例代码如下:

RestTemplate restTemplate = new RestTemplate();
System.out.println(restTemplate.getRequestFactory());
ResponseEntity<String> response = restTemplate.getForEntity("https://blog.csdn.net", String.class);
HttpHeaders headers = response.getHeaders();
System.out.println("Response Headers: " + headers);

代码打印包含:Connection:“keep-alive”。

代码追踪:
restTemplate.getForEntity->this.execute->this.doExecute->this.createRequest->this.getRequestFactory().createRequest
可以看到先获取了请求工厂然后才建立连接的。追踪一下SimpleClientHttpRequestFactory的实现

    public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {HttpURLConnection connection = this.openConnection(uri.toURL(), this.proxy);this.prepareConnection(connection, httpMethod.name());return (ClientHttpRequest)(this.bufferRequestBody ? new SimpleBufferingClientHttpRequest(connection, this.outputStreaming) : new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming));}

openConnection 方法:
这个方法创建一个新的 HttpURLConnection 实例。openConnection 通常会调用 URL.openConnection() 方法,这实际上是创建一个新的连接对象。该连接是通过 HttpURLConnection 类建立的,它负责处理 TCP 连接的创建和管理。

prepareConnection 方法:
在这一步,prepareConnection 方法配置 HttpURLConnection 对象,例如设置请求方法(GET、POST 等)、请求头以及其他必要的配置。

SimpleBufferingClientHttpRequest 和 SimpleStreamingClientHttpRequest:
根据 bufferRequestBody 的值,返回一个适当的 ClientHttpRequest 实例。SimpleBufferingClientHttpRequest 和 SimpleStreamingClientHttpRequest 都是对 HttpURLConnection 的封装,负责处理请求的具体细节。

总结:
SimpleClientHttpRequestFactory 在每次调用 createRequest 时都会创建一个新的 HttpURLConnection 实例。虽然 HttpURLConnection 可以复用连接(通过 HTTP/1.1 的 Keep-Alive 特性),但 SimpleClientHttpRequestFactory 本身不管理连接池或长期连接的复用。

3. RestTemplate使用长连接

简单实现:

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;public static void main(String[] args) {CloseableHttpClient httpClient = HttpClients.custom().setMaxConnTotal(100).setMaxConnPerRoute(20).build();HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);RestTemplate restTemplate = new RestTemplate(factory);System.out.println(restTemplate.getRequestFactory());ResponseEntity<String> response = restTemplate.getForEntity("https://blog.csdn.net", String.class);HttpHeaders headers = response.getHeaders();System.out.println("Response Headers: " + headers);}

复杂实现:

HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();try {// 设置信任ssl访问SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();httpClientBuilder.setSSLContext(sslContext);HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()// 注册http和https请求.register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslConnectionSocketFactory).build();// 使用Httpclient连接池的方式配置PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);poolingHttpClientConnectionManager.setMaxTotal(200);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20);httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);CloseableHttpClient httpClient = httpClientBuilder.build();HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);RestTemplate restTemplate = new RestTemplate(factory);} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {logger.error("初始化Httpclient连接池出错", e);}return null;

建议:
如果你的应用有特定的安全要求或协议需求(比如使用特定的证书、主机名验证规则等),建议你使用自定义的 SSLConnectionSocketFactory 和 Registry,即复杂实现。如果你的应用场景对默认配置没有特殊要求,可以使用默认配置,即简单实现。

具体区别如下:
HTTPS 连接的 SSL/TLS 配置:
SSL/TLS 设置:如果你省略了 SSLConnectionSocketFactory 的设置,HTTPS 连接将使用默认的 SSL/TLS 配置。这可能会导致你无法使用自定义的信任策略或证书设置。
主机名验证:省略 HostnameVerifier 相关的设置将导致默认的主机名验证机制被应用,可能会有不同的验证标准。

连接工厂注册:
注册表配置:省略 Registry 的设置,将会失去对 HTTP 和 HTTPS 连接工厂的自定义管理。这可能会导致连接池无法正确处理不同协议的连接,从而影响连接的创建和管理。

连接池行为:
连接工厂选择:如果你不提供自定义的 Registry,连接池可能无法正确区分和使用 HTTP 和 HTTPS 连接工厂,从而可能导致连接创建或复用的问题。

默认配置影响:
安全性:默认的 SSL 配置可能不符合你特定的安全要求。如果你需要特定的证书信任策略或加密设置,省略自定义配置会导致无法满足这些要求。
兼容性:如果你与特定的服务或API有特定的兼容性需求,默认配置可能不满足这些需求。

这篇关于RestTemplate使用长连接的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1113438

相关文章

W外链微信推广短连接怎么做?

制作微信推广链接的难点分析 一、内容创作难度 制作微信推广链接时,首先需要创作有吸引力的内容。这不仅要求内容本身有趣、有价值,还要能够激起人们的分享欲望。对于许多企业和个人来说,尤其是那些缺乏创意和写作能力的人来说,这是制作微信推广链接的一大难点。 二、精准定位难度 微信用户群体庞大,不同用户的需求和兴趣各异。因此,制作推广链接时需要精准定位目标受众,以便更有效地吸引他们点击并分享链接

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

【北交大信息所AI-Max2】使用方法

BJTU信息所集群AI_MAX2使用方法 使用的前提是预约到相应的算力卡,拥有登录权限的账号密码,一般为导师组共用一个。 有浏览器、ssh工具就可以。 1.新建集群Terminal 浏览器登陆10.126.62.75 (如果是1集群把75改成66) 交互式开发 执行器选Terminal 密码随便设一个(需记住) 工作空间:私有数据、全部文件 加速器选GeForce_RTX_2080_Ti