Spring web之restTemplate超时问题处理
问题
项目中有个远程服务因为某些原因会访问不通,于是就在调用的那一步挂起无法结束了。
查看代码
代码大概如下
CloseableHttpClient closeableHttpClient = HttpClients.custom() .setConnectionManager(manager) .build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();requestFactory.setHttpClient(httpClient);clientHttpRequestFactory.setConnectTimeout(1000);RestTemplate restTemplate = new RestTemplate();restTemplate.setRequestFactory(requestFactory);
分析
HttpComponentsClientHttpRequestFactory底层默认使用了apache的HttpClient,超时设置就针对其设置的。其实我们只需要设置ReadTimeout就好了。
CloseableHttpClient closeableHttpClient = HttpClients.custom()
.setConnectionManager(manager)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
clientHttpRequestFactory.setConnectTimeout(1000);
clientHttpRequestFactory.setReadTimeout(50);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(requestFactory);
但我们发现,我们并没有使用默认的HttpClient,而是显式的指定了Client,我们在创建Client的时候也可以指定其的各种超时属性:
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setConnectTimeout(2 * 1000)
.setSocketTimeout(5 * 1000)
.setConnectionRequestTimeout(2 * 1000)
.build(); CloseableHttpClient closeableHttpClient = HttpClients.custom()
.setDefaultRequestConfig(getRequestConfig())
.setConnectionManager(manager)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
clientHttpRequestFactory.setConnectTimeout(1000);
clientHttpRequestFactory.setReadTimeout(50);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(requestFactory);
上面可以看到,我们在创建Client的时候指定了超时时间,也在创建HttpComponentsClientHttpRequestFactory的时候指定了超时时间,那么到底以哪个为准呢?
一探究竟
项目中使用的是spring web 4.3.5, 我们看看源代码的实现,以下是HttpComponentsClientHttpRequestFactory类的部分方法:
/**
* Set the socket read timeout for the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout.
* <p>Additional properties can be configured by specifying a
* {@link RequestConfig} instance on a custom {@link HttpClient}.
* @param timeout the timeout value in milliseconds
* @see RequestConfig#getSocketTimeout()
*/
public void setReadTimeout(int timeout) {
Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
this.requestConfig = requestConfigBuilder().setSocketTimeout(timeout).build();
setLegacySocketTimeout(getHttpClient(), timeout);
}
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest);
HttpContext context = createHttpContext(httpMethod, uri);
if (context == null) {
context = HttpClientContext.create();
} // Request configuration not set in the context
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
// Use request configuration given by the user, when available
RequestConfig config = null;
if (httpRequest instanceof Configurable) {
config = ((Configurable) httpRequest).getConfig();
}
if (config == null) {
config = createRequestConfig(getHttpClient());
}
if (config != null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
}
} if (this.bufferRequestBody) {
return new HttpComponentsClientHttpRequest(getHttpClient(), httpRequest, context);
}
else {
return new HttpComponentsStreamingClientHttpRequest(getHttpClient(), httpRequest, context);
}
}
/**
* Create a default {@link RequestConfig} to use with the given client.
* Can return {@code null} to indicate that no custom request config should
* be set and the defaults of the {@link HttpClient} should be used.
* <p>The default implementation tries to merge the defaults of the client
* with the local customizations of this factory instance, if any.
* @param client the {@link HttpClient} (or {@code HttpAsyncClient}) to check
* @return the actual RequestConfig to use (may be {@code null})
* @since 4.2
* @see #mergeRequestConfig(RequestConfig)
*/
protected RequestConfig createRequestConfig(Object client) {
if (client instanceof Configurable) {
RequestConfig clientRequestConfig = ((Configurable) client).getConfig();
return mergeRequestConfig(clientRequestConfig);
}
return this.requestConfig;
}
/**
* Merge the given {@link HttpClient}-level {@link RequestConfig} with
* the factory-level {@link RequestConfig}, if necessary.
* @param clientConfig the config held by the current
* @return the merged request config
* @since 4.2
*/
protected RequestConfig mergeRequestConfig(RequestConfig clientConfig) {
if (this.requestConfig == null) { // nothing to merge
return clientConfig;
} RequestConfig.Builder builder = RequestConfig.copy(clientConfig);
int connectTimeout = this.requestConfig.getConnectTimeout();
if (connectTimeout >= 0) {
builder.setConnectTimeout(connectTimeout);
}
int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout();
if (connectionRequestTimeout >= 0) {
builder.setConnectionRequestTimeout(connectionRequestTimeout);
}
int socketTimeout = this.requestConfig.getSocketTimeout();
if (socketTimeout >= 0) {
builder.setSocketTimeout(socketTimeout);
}
return builder.build();
}
我们可以看到,版本4.2之后,如果二者都进行了参数指定,会有一个mergeRequestConfig的操作,超时以HttpComponentsClientHttpRequestFactory类指定为为准。
结论
所以,针对本文一开始的问题,我们只需要设置HttpComponentsClientHttpRequestFactory实例的setReadTimeout方法即可。
参考
https://leokongwq.github.io/2018/11/21/springboot-resttempate-timout.html
https://www.cnblogs.com/softidea/p/6964347.html
但我们发现,我们显式的指定了Client,我们在创建Client的时候可以指定其的各种超时属性:
Spring web之restTemplate超时问题处理的更多相关文章
- Spring Cloud ZooKeeper集成Feign的坑1,错误:Consider defining a bean of type 'org.springframework.web.client.RestTemplate' in your configuration.
错误如下: ERROR 31473 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** A ...
- spring web.xml 难点配置总结
web.xml web.xml是所有web项目的根源,没有它,任何web项目都启动不了,所以有必要了解相关的配置. ContextLoderListener,ContextLoaderServlet, ...
- Spring Boot使用RestTemplate消费REST服务的几个问题记录
我们可以通过Spring Boot快速开发REST接口,同时也可能需要在实现接口的过程中,通过Spring Boot调用内外部REST接口完成业务逻辑. 在Spring Boot中,调用REST Ap ...
- spring web.xml 难点配置总结【转】
web.xml web.xml是所有web项目的根源,没有它,任何web项目都启动不了,所以有必要了解相关的配置. ContextLoderListener,ContextLoaderServlet, ...
- 001-快速搭建Spring web应用【springboot 2.0.4】-gradle、springboot的启动过程分析、gradle多模块构建
一.概述 学习<精通Spring MVC4>书籍笔记 二.笔记 1.快速构建Spring starter web项目几种方式 1>使用Spring Tool Suite生成Start ...
- spring boot 注入 restTemplate
转载自:http://blog.csdn.net/liuchuanhong1/article/details/54631080 package com.chhliu.springboot.restfu ...
- Spring WebClient vs. RestTemplate
1. 简介 本教程中,我们将对比 Spring 的两种 Web 客户端实现 -- RestTemplate 和 Spring 5 中全新的 Reactive 替代方案 WebClient. 2. 阻塞 ...
- 使用 Spring 提供的 restTemplate 完成 Http 服务消费
RestTemplate 介绍 RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 Http 服务的方法,能够大大提高 ...
- Consider defining a bean of type 'org.springframework.web.client.RestTemplate' in your configuration
https://www.cnblogs.com/EasonJim/p/7546136.html 错误如下: ERROR 31473 --- [ main] o.s.b.d.LoggingFailure ...
随机推荐
- (十三)利用BASE_DIR来import模板
实际工程的组织架构一般是这样的: bin包下的bin.py是实际的执行文件,my_mould包下的是业务逻辑的实现模板 bin.py需要import my_mould下的py文件,而bin和my_mo ...
- 【Oracle】Oracle中chr()的含义
oracle中chr含义 CHR(10)和 CHR(13)--在oracle都为换行 chr(32)--表示空格 DECLARE v_a VARCHAR2(255); v_b VARCHAR2(255 ...
- SpringBoot Logback无法获取配置中心属性
SpringBoot Logback无法获取配置中心属性 前言 最近在做项目中,需要把项目中的日志信息通过RabbitMQ将规定格式的消息发送到消息队列中,然后ELK系统通过消息队列拿日志并且保存起来 ...
- nodejs内网穿透
说明 本地服务注册,基于子域名->端口映射.公网测试请开启二级或三级域名泛解析 无心跳保活.无多线程并发处理 服务器端 请求ID基于全局变量,不支持PM2多进程开服务端.(多开请修改uid函数, ...
- 24V转5V稳压芯片,高效率的同步降压DC-DC变换器3A输出电流
PW2330开发了一种高效率的同步降压DC-DC变换器3A输出电流.PW2330在4.5V到30V的宽输入电压范围内工作集成主开关和同步开关,具有非常低的RDS(ON)以最小化传导损失.PW2330采 ...
- 1.2V升5V电源芯片,1.2V升3V的IC电路图方案
镍氢电池就是典型的1.2V供电电源了,但是1.2V电压太低,需要电源芯片来1.2V升5V输出,或1.2V升3V输出稳压,1.2V单独难给其他芯片或者模块供电,即使串联1.2V*2=2.4V,也是因为电 ...
- css-前端实现左中右三栏布局的常用方法:绝对定位,圣杯,双飞翼,flex,table-cell,网格布局等
1.前言 作为一个前端开发人员,工作学习中经常会遇到快速构建网页布局的情况,这篇我整理了一下我知道的一些方法.我也是第一次总结,包括圣杯布局,双飞翼布局,table-cell布局都是第一次听说,可能会 ...
- Android事件分发机制四:学了事件分发有什么用?
" 学了事件分发,影响我CV大法吗?" " 影响我陪女朋友的时间" " ..... " 前言 Android事件分发机制已经来到第四篇了,在 ...
- Devexpress DockManager多页面浮动窗口会关闭所有页面的问题
注册 DockManager 的 ClosingPanel 事件 private void DockManager1_ClosingPanel(object sender, DockPanelCanc ...
- zabbix指定版本自动化安装脚本shell
安装服务端zabbix 有时候要部署一个zabbix各种配置啊贼烦. #!/bin/sh #sleep 10 zabbix_version=4.2.5 ###这里你自定义版本,我要的是4.2.5 za ...