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