网站首页 > 技术文章 正文
springboot中使用spring-boot-starter-web自带RestTemplate
自定义HttpComponentsClientHttpRequestFactory 需要引用maven坐标
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
代码配置:
//读取properties配置
@Configuration
@ConfigurationProperties(prefix = "resttemplate-http-pool")
public class RestTemplateConfigProperties {
private int connectionRequestTimeout = 1000;
private int connectionTimeout = 2 * 1000;
private int socketTimeout = 3 * 1000;
private int maxPerRoute = 10;
private int maxTotal = 50;
private int validateAfterInactivity = 3 * 1000;
private int maxIdleTime = 30 * 1000;
private int retryTimes = 0;
//省略 get、set
}
@Configuration
public class RestTemplateConfig {
private Logger logger = LoggerFactory.getLogger(RestTemplateConfig.class);
@Autowired
private RestTemplateConfigProperties restTemplateConfigProperties;
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient()));
restTemplate.setErrorHandler(new CustomErrorHandler());
return restTemplate;
}
@Bean
public HttpClient httpClient() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(restTemplateConfigProperties.getMaxTotal());
connectionManager.setDefaultMaxPerRoute(restTemplateConfigProperties.getMaxPerRoute());
//在从连接池获取连接时,连接不活跃多长时间后需要进行一次验证,默认为2s
connectionManager.setValidateAfterInactivity(restTemplateConfigProperties.getValidateAfterInactivity());
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(restTemplateConfigProperties.getSocketTimeout())
.setConnectTimeout(restTemplateConfigProperties.getConnectionTimeout())
.setConnectionRequestTimeout(restTemplateConfigProperties.getConnectionRequestTimeout())
.build();
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
//定期回收空闲连接
.evictIdleConnections(restTemplateConfigProperties.getMaxIdleTime(), TimeUnit.MILLISECONDS)
//回收过期连接
.evictExpiredConnections();
if (restTemplateConfigProperties.getRetryTimes() > 0) {
httpClientBuilder.setRetryHandler(handler);
} else {
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
}
CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
/**
*JVM停止或重启时,关闭连接池释放掉连接
*/
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
logger.info("closing http client");
closeableHttpClient.close();
logger.info("http client closed");
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}));
return closeableHttpClient;
}
static class CustomErrorHandler implements ResponseErrorHandler {
//自定义异常处理方式这个配置是当RestTemplate 请求异常时将错误返回给使用者自行处理,
//而不是抛出异常导致使用者无法获取调用情况。
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return true;
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
}
}
//重试策略,注意幂等操作,不需要可以使用默认的
HttpRequestRetryHandler handler = (arg0, retryTimes, arg2) -> {
if (retryTimes > restTemplateConfigProperties.getRetryTimes()) {
return false;
}
//Timeout
if (arg0 instanceof InterruptedIOException) {
return false;
}
//Unknown host
if (arg0 instanceof UnknownHostException) {
return false;
}
//SSL handshake exception
if (arg0 instanceof SSLException) {
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(arg2);
HttpRequest request = clientContext.getRequest();
//如果请求类型不是HttpEntityEnclosingRequest,被认为是幂等的,那么就重试
//HttpEntityEnclosingRequest指的是有请求体的request,比HttpRequest多一个Entity属性
//而常用的GET请求是没有请求体的,POST、PUT都是有请求体的
//Rest一般用GET请求获取数据,故幂等,POST用于新增数据,故不幂等
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
return idempotent;
};
}
重点参数解释
maxPerRoute:
服务1要通过httpclient调用服务2的接口。服务1发送了400个请求,当设置maxPerRoute=100,MaxTotal=200,接口执行时间为500ms,由于maxPerRoute=100,所以要分为100,100,100,100分四批来执行,全部执行完成需要2000ms。而如果maxPerRoute设置为400,全部执行完需要500ms。在这种情况下(提供并发能力时)就要对这两个参数进行设置了。
MaxTotal:
限制多个maxPerRoute总数不能大于该参数;
connectTimeOut:
指建立连接的超时时间,比较容易理解
connectionRequestTimeOut:
指从连接池获取到连接的超时时间,如果是非连接池的话,该参数暂时没有发现有什么用处
socketTimeOut:
指客户端和服务进行数据交互的时间,是指两者之间如果两个数据包之间的时间大于该时间则认为超时,而不是整个交互的整体时间,比如如果设置1秒超时,如果每隔0.8秒传输一次数据,传输10次,总共8秒,这样是不超时的。而如果任意两个数据包之间的时间超过了1秒,则超时。
properties配置属性:
resttemplate-http-pool.connectionRequestTimeout=60000
resttemplate-http-pool.connectionTimeout=60000
resttemplate-http-pool.socketTimeout=60000
resttemplate-http-pool.maxPerRoute=10
resttemplate-http-pool.maxTotal=50
resttemplate-http-pool.validateAfterInactivity=3000
resttemplate-http-pool.maxIdleTime=30000
resttemplate-http-pool.retryTimes=3
封装工具类:
//post表单类型
public String postForm(String targetUrl, MultiValueMap<String, Object> paraMap) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(paraMap, headers);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(targetUrl, request, String.class);
return responseEntity.getBody();
}
//post json类型
public String postJson(String targetUrl, String jsonPara) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity(jsonPara, headers);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(targetUrl, request, String.class);
return responseEntity.getBody();
}
//get http://127.0.0.1:9513/httpTestC/formUriVariablesTestReceive?key1=val1&key2=val2类型
public String getWithUriAppend(String targetUrl, Map<String, Object> paraMap) {
if (paraMap == null || paraMap.isEmpty()) {
ResponseEntity<String> responseEntity = restTemplate.getForEntity(targetUrl, String.class);
return responseEntity.getBody();
}
StringBuffer url = new StringBuffer(targetUrl.concat("?"));
for (Map.Entry<String, Object> entry : paraMap.entrySet()) {
url.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
targetUrl = StringUtils.substringBeforeLast(url.toString(), "&");
ResponseEntity<String> responseEntity = restTemplate.getForEntity(targetUrl, String.class, paraMap);
return responseEntity.getBody();
}
//get http://127.0.0.1:9513/httpTestC/formGetTestReceive/{key1}/{key2} 类型
public String getWithUriVariables(String targetUrl, Map<String, Object> paraMap) {
if (paraMap == null || paraMap.isEmpty()) {
ResponseEntity<String> responseEntity = restTemplate.getForEntity(targetUrl, String.class);
return responseEntity.getBody();
}
StringBuffer url = new StringBuffer(targetUrl);
for (Map.Entry<String, Object> entry : paraMap.entrySet()) {
url.append("/").append("{").append(entry.getKey()).append("}");
}
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url.toString(), String.class, paraMap);
return responseEntity.getBody();
}
猜你喜欢
- 2024-11-24 使用Knative部署基于Spring Native的微服务
- 2024-11-24 阿里p7大佬首次分享Spring Cloud学习笔记,带你从0搭建微服务
- 2024-11-24 ElasticSearch进阶篇之搞定在SpringBoot项目中的实战应用
- 2024-11-24 SpringCloud微服务架构实战:类目管理微服务开发
- 2024-11-24 SpringBoot+SpringCloud题目整理
- 2024-11-24 《github精选系列》——SpringBoot 全家桶
- 2024-11-24 Springboot2.0学习2 超详细创建restful服务步骤
- 2024-11-24 SpringCloud系列:多模块聚合工程基本环境搭建「1」
- 2024-11-24 Spring Cloud Consul快速入门Demo
- 2024-11-24 Spring Cloud Contract快速入门Demo
- 最近发表
-
- 使用Knative部署基于Spring Native的微服务
- 阿里p7大佬首次分享Spring Cloud学习笔记,带你从0搭建微服务
- ElasticSearch进阶篇之搞定在SpringBoot项目中的实战应用
- SpringCloud微服务架构实战:类目管理微服务开发
- SpringBoot+SpringCloud题目整理
- 《github精选系列》——SpringBoot 全家桶
- Springboot2.0学习2 超详细创建restful服务步骤
- SpringCloud系列:多模块聚合工程基本环境搭建「1」
- Spring Cloud Consul快速入门Demo
- Spring Cloud Contract快速入门Demo
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)