首页 > 其他分享 >restTemplate做长连接

restTemplate做长连接

时间:2022-12-21 12:03:00浏览次数:38  
标签:return int restTemplate public 重试 做长 mysql 连接


restTemplate是springboot自带的http请求客户端,里面包装了HttpClient,是在SpringBoot项目中进行http请求常用的方式,本篇文章主要是讲解怎么进行restTemplate的长连接

一、普通情况下的RestTemplate配置

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

二、长连接的配置

下面说下怎么进行RestTemplate的配置

@Bean
public RestTemplate AchiementTemplateLongConnection(RestTemplateBuilder builder) {
return builder.requestFactory(()->httpComponentsClientHttpRequestFactory())
.build();
}

@Bean
public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpClient(poolingHttpClientConnectionManager(),requestConfig()));
return factory;
}

@Bean
public RequestConfig requestConfig() {
RequestConfig result = RequestConfig.custom()
.setConnectionRequestTimeout(0)
.setConnectTimeout(CONNECTION_TIMEOUT)
.setSocketTimeout(CONNECTION_TIMEOUT)
.build();

return result;
}

@Bean
public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager poolingHttpClientConnectionManager, RequestConfig requestConfig) {
CloseableHttpClient result = HttpClientBuilder
.create()
.setConnectionManager(poolingHttpClientConnectionManager)
.setDefaultRequestConfig(requestConfig)
.setRetryHandler(new AchivmentGetHttpRequestRetryHandler(1,true))
.build();

return result;
}

@Bean
public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setValidateAfterInactivity(2000);
return connectionManager;
}

下面对几个方法返回的类进行解释下:

  • httpClient:http请求的客户端
  • RequestConfig:httpClient请求的配置包括超时时间等
  • PoolingHttpClientConnectionManager:设置连接池,节省了创建连接的开销

三、长连接中需要注意的问题

试想一个问题,长连接是有时间的,不管是8小时还是2小时,当连接断开了,怎么重连是需要处理的,有两种方式可以进行处理:

  1. 连接之前先校验下连接是否通着,mysql的长连接就是通过ping命令去校验的
  2. 做重试,RestTemplate就是这么做的,捕获IOException,然后进行重试,因为之前断开的连接在第一次失败后,被销毁了,后面再一次重试即可成功了。

==注:==这里要特别说明下,httpComponents包里面并没有那么傻,自己断开的连接自己肯定可以感知的,但是当你是客户端,而服务端单方面断开连接的时候,就感知不到了。

最开始我是在检查,我代码中已经设置的检验,为何还是检验不出来呢,我设置检验的代码如下:

connectionManager.setValidateAfterInactivity(2000);

为何检验的代码没有生效呢?原因在这里:BHttpConnectionBase类的方法

@Override
public boolean isStale() {
if (!isOpen()) {
return true;
}
try {
final int bytesRead = fillInputBuffer(1);
return bytesRead < 0;
} catch (final SocketTimeoutException ex) {
//如果是SocketTimeoutException
return false;
} catch (final IOException ex) {
return true;
}
}

我们看下当服务端关闭连接的时候,客户端报什么异常:

java.net.SocketInputStream.socketRead0(Native Method)抛出了timeoutException

正好是返回连接没有问题,就是说这个检验是无效的。

那这个时候只能重试了:
在RestTemplate中使用了DefaultHttpRequestRetryHandler类进行重试,里面有一个retryRequest方法就是用来判断是否重试的。里面有这么一段代码

if (handleAsIdempotent(request)) {
// Retry if the request is considered idempotent
return true;
}

这段代码是判断是否有消息体,如果有消息体则不能重试,这是为了避免如果是插入或者修改的方法,不能轻易重试,否则会有风险。但是如果你的查询请求是post,那么也不会重试,可以自己实现一个retryHandler解决此问题。

四、最后

我贴上mysql的ping逻辑,在此方法中:
com.mysql.jdbc.ConnectionImpl#execSQL(com.mysql.jdbc.StatementImpl, java.lang.String, int, com.mysql.jdbc.Buffer, int, int, boolean, java.lang.String, com.mysql.jdbc.Field[], boolean)

public ResultSetInternalMethods execSQL(StatementImpl callingStatement, String sql, int maxRows, Buffer packet, int resultSetType, int resultSetConcurrency,
boolean streamResults, String catalog, Field[] cachedMetadata, boolean isBatch) throws SQLException {
synchronized (getConnectionMutex()) {
//
// Fall-back if the master is back online if we've issued queriesBeforeRetryMaster queries since we failed over
//

long queryStartTime = 0;

int endOfQueryPacketPosition = 0;

if (packet != null) {
endOfQueryPacketPosition = packet.getPosition();
}

if (getGatherPerformanceMetrics()) {
queryStartTime = System.currentTimeMillis();
}

this.lastQueryFinishedTime = 0; // we're busy!

if ((getHighAvailability()) && (this.autoCommit || getAutoReconnectForPools()) && this.needsPing && !isBatch) {
try {
pingInternal(false, 0);

this.needsPing = false;
} catch (Exception Ex) {
createNewIO(true);
}
}


标签:return,int,restTemplate,public,重试,做长,mysql,连接
From: https://blog.51cto.com/u_11970680/5959701

相关文章

  • linux远程连接注意防火墙
    当我们远程连接linux服务器的时候,有时候会遇到连接不上服务器的情况,在确定一切都没问题的时候,那很可能就是防火墙开启了,此时我们只要关闭防火墙就行了。命令如下:serviceipt......
  • GreatSQL MGR 使用 IPv6 连接
    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。作者:王权富贵文章来源:社区原创1.概述本......
  • Mybatis 连接池,事务,动态sql
    1、连接池pooled用连接池unpooled不用连接池<dataSourcetype="POOLED"><propertyname="driver"value="${jdbc.driver}"/><propertyname="url"value="${jdbc.ur......
  • python 运程连接 linux
    python实现远程连接,操作linux1.安装依赖pip3installparamiko2.实现原理#-*-coding:utf-8-*-importparamikodefconnect(cmd,try_times=3):while......
  • wget下载Git拒绝连接
    执行:gitconfig--globalurl."https://".insteadOfgit:// Cloninginto'k8s-ha-install'...fatal:unabletoaccess'https://github.com/dotbalo/k8s-ha-install.......
  • c++ 通过ODBC连接达梦数据库
    安装达梦数据库建立数据源,位置:开始》》windows管理工具》》ODBC数据源  测试通过 打开编译器编写代码连接这个数据库 #include"stdafx.h"#include<Windows.......
  • Java实现基本MySQL连接 - 数据的基本操作
    importjava.sql.*;publicclassMain{//MySQL8.0以下版本-JDBC驱动名及数据库URL//staticfinalStringJDBC_DRIVER="com.mysql.jdbc.Driver";......
  • 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。
    今天连接远程数据库,又出现了这个问题。解决方法也很简单,记录一下吧。    出现这个问题错误一般有俩种。一、服务器的ipv4输入错误。这种情况进入电脑属性就可以......
  • 连接到 Mac 的外置显示器画面模糊怎么办?
    Mac外置显示器无法连接?Mac外置显示器画面模糊怎么办?下面就和小编一起来看看吧!检查线缆或转换器断开外置显示器的线缆与Mac的连接,然后重新连接。如果外置显示器的线缆无法......
  • 保持 SSH 连接
    SSH总是被强行中断,尤其是用VSCode代码写的好好的,突然刷新窗口,不仅效率低,更惹人恼火。可以通过配置服务端或客户端的SSH来保持SSH链接:方法一:配置服务端可以在服务......