spring boot封装HttpClient
由 admin 发表于 10:53package com.example.httpclient.httpclient;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpResponse;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 描述:连接保持策略
* @author chhliu
*/
@Configuration
public class MyconnectionKeepAliveStrategy {
@Value("${httpclient.config.keepAliveTime}")
private int keepAliveTime = 30;
@Bean("connectionKeepAliveStrategy")
public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
return new ConnectionKeepAliveStrategy() {
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
} catch (NumberFormatException ignore) {
}
}
}
return 30 * 1000;
}
};
}
}
package com.example.httpclient.httpclient;
import org.apache.http.HttpHost;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 描述:HttpClient代理
* @author chhliu
*/
@Configuration
public class MyDefaultProxyRoutePlanner {
@Value("${httpclient.config.proxyhost}")
private String proxyHost ="127.0.0.1";
@Value("${httpclient.config.proxyPort}")
private int proxyPort = 8080;
@Bean
public DefaultProxyRoutePlanner defaultProxyRoutePlanner(){
HttpHost proxy = new HttpHost(this.proxyHost, this.proxyPort);
return new DefaultProxyRoutePlanner(proxy);
}
}
package com.example.httpclient.httpclient;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.protocol.HttpContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
/**
* 描述:HttpClient的重试处理机制
*/
@Configuration
public class MyhttpRequestRetryHandler {
@Value("${httpclient.config.retryTime}")// 此处建议采用@ConfigurationProperties(prefix="httpclient.config")方式,方便复用
private int retryTime;
@Bean
public HttpRequestRetryHandler httpRequestRetryHandler() {
// 请求重试
final int retryTime = this.retryTime;
return new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
// Do not retry if over max retry count,如果重试次数超过了retryTime,则不再重试请求
if (executionCount >= retryTime) {
return false;
}
// 服务端断掉客户端的连接异常
if (exception instanceof NoHttpResponseException) {
return true;
}
// time out 超时重试
if (exception instanceof InterruptedIOException) {
return true;
}
// Unknown host
if (exception instanceof UnknownHostException) {
return false;
}
// Connection refused
if (exception instanceof ConnectTimeoutException) {
return false;
}
// SSL handshake exception
if (exception instanceof SSLException) {
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
if (!(request instanceof HttpEntityEnclosingRequest)) {
return true;
}
return false;
}
};
}
}
package com.example.httpclient.httpclient;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
public class MyPoolingHttpClientConnectionManager {
/**
* 连接池最大连接数
*/
@Value("${httpclient.config.connMaxTotal}")
private int connMaxTotal = 20;
/**
*
*/
@Value("${httpclient.config.maxPerRoute}")
private int maxPerRoute = 20;
/**
* 连接存活时间,单位为s
*/
@Value("${httpclient.config.timeToLive}")
private int timeToLive = 60;
@Bean
public PoolingHttpClientConnectionManager poolingClientConnectionManager(){
PoolingHttpClientConnectionManager poolHttpcConnManager = new PoolingHttpClientConnectionManager(60, TimeUnit.SECONDS);
// 最大连接数
poolHttpcConnManager.setMaxTotal(this.connMaxTotal);
// 路由基数
poolHttpcConnManager.setDefaultMaxPerRoute(this.maxPerRoute);
return poolHttpcConnManager;
}
}
package com.example.httpclient.httpclient;
import org.apache.http.client.config.RequestConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRequestConfig {
@Value("${httpclient.config.connectTimeout}")
private int connectTimeout = 2000;
@Value("${httpclient.config.connectRequestTimeout}")
private int connectRequestTimeout = 2000;
@Value("${httpclient.config.socketTimeout}")
private int socketTimeout = 2000;
@Bean
public RequestConfig config(){
return RequestConfig.custom()
.setConnectionRequestTimeout(this.connectRequestTimeout)
.setConnectTimeout(this.connectTimeout)
.setSocketTimeout(this.socketTimeout)
.build();
}
}
package com.example.httpclient.httpclient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 描述:HttpClient客户端封装
*/
@Service("httpClientManagerFactoryBen")
public class HttpClientManagerFactoryBen implements FactoryBean<CloseableHttpClient>, InitializingBean, DisposableBean {
/**
* FactoryBean生成的目标对象
*/
private CloseableHttpClient client;
@Autowired
private ConnectionKeepAliveStrategy connectionKeepAliveStrategy;
@Autowired
private HttpRequestRetryHandler httpRequestRetryHandler;
//@Autowired
//private DefaultProxyRoutePlanner proxyRoutePlanner;
@Autowired
private PoolingHttpClientConnectionManager poolHttpcConnManager;
@Autowired
private RequestConfig config;
// 销毁上下文时,销毁HttpClient实例
@Override
public void destroy() throws Exception {
/*
* 调用httpClient.close()会先shut down connection manager,然后再释放该HttpClient所占用的所有资源,
* 关闭所有在使用或者空闲的connection包括底层socket。由于这里把它所使用的connection manager关闭了,
* 所以在下次还要进行http请求的时候,要重新new一个connection manager来build一个HttpClient,
* 也就是在需要关闭和新建Client的情况下,connection manager不能是单例的.
*/
if(null != this.client){
this.client.close();
}
}
@Override// 初始化实例
public void afterPropertiesSet() throws Exception {
/*
* 建议此处使用HttpClients.custom的方式来创建HttpClientBuilder,而不要使用HttpClientBuilder.create()方法来创建HttpClientBuilder
* 从官方文档可以得出,HttpClientBuilder是非线程安全的,但是HttpClients确实Immutable的,immutable 对象不仅能够保证对象的状态不被改变,
* 而且还可以不使用锁机制就能被其他线程共享
*/
this.client = HttpClients.custom().setConnectionManager(poolHttpcConnManager)
.setRetryHandler(httpRequestRetryHandler)
.setKeepAliveStrategy(connectionKeepAliveStrategy)
//.setRoutePlanner(proxyRoutePlanner)
.setDefaultRequestConfig(config)
.build();
}
// 返回实例的类型
@Override
public CloseableHttpClient getObject() throws Exception {
return this.client;
}
@Override
public Class<?> getObjectType() {
return (this.client == null ? CloseableHttpClient.class : this.client.getClass());
}
// 构建的实例为单例
@Override
public boolean isSingleton() {
return true;
}
}
application.properties
# 代理的host httpclient.config.proxyhost=127.0.0.1 ## 代理端口 httpclient.config.proxyPort=8080 # 连接超时或异常重试次数 httpclient.config.retryTime=1 # 长连接保持时间,单位为s httpclient.config.keepAliveTime=30 # 连接池最大连接数 httpclient.config.connMaxTotal=20 httpclient.config.maxPerRoute=20 # 连接超时时间,单位ms httpclient.config.connectTimeout=1000 # 请求超时时间 httpclient.config.connectRequestTimeout=1000 # sock超时时间 httpclient.config.socketTimeout=1000 # 连接存活时间,单位s httpclient.config.timeToLive=60
