浏览代码

http连接池

liuam 7 年之前
父节点
当前提交
d13f467f2f

+ 33 - 0
src/main/java/com/uas/ps/inquiry/http/HttpAsyncCallback.java

@@ -0,0 +1,33 @@
+package com.uas.ps.inquiry.http;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.concurrent.FutureCallback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * 异步 http 请求回调
+ * @author liuam
+ * @since 2018/8/28 0028 上午 0:00
+ */
+@Component
+public class HttpAsyncCallback implements FutureCallback<HttpResponse> {
+
+    private static final Logger logger = LoggerFactory.getLogger(HttpAsyncCallback.class);
+
+    @Override
+    public void completed(HttpResponse response) {
+
+    }
+
+    @Override
+    public void failed(Exception e) {
+
+    }
+
+    @Override
+    public void cancelled() {
+
+    }
+}

+ 188 - 0
src/main/java/com/uas/ps/inquiry/http/HttpClientSpringFactory.java

@@ -0,0 +1,188 @@
+package com.uas.ps.inquiry.http;
+
+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.config.RequestConfig;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
+import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
+import org.apache.http.impl.nio.reactor.IOReactorConfig;
+import org.apache.http.nio.reactor.ConnectingIOReactor;
+import org.apache.http.nio.reactor.IOReactorException;
+import org.apache.http.protocol.HttpContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.SocketException;
+
+/**
+ * http 同步连接池、http 异步连接池,与spring集成
+ * @author liuam
+ * @since 2018/8/27 0027 下午 15:58
+ */
+@Component
+public class HttpClientSpringFactory {
+
+    private static final Logger logger = LoggerFactory.getLogger(HttpClientSpringFactory.class);
+
+    @Value("${http.asyncConnectTimeout}")
+    private Integer asyncConnectTimeout;
+
+    @Value("${http.asyncSocketTimeout}")
+    private Integer asyncSocketTimeout;
+
+    @Value("${http.asyncConnectionRequestTimeout}")
+    private Integer asyncConnectionRequestTimeout;
+
+    @Value("${http.asyncConnectNum}")
+    private Integer asyncConnectNum;
+
+    @Value("${http.asyncConnectPerRoute}")
+    private Integer asyncConnectPerRoute;
+
+    @Value("${http.asyncIoThreadCount}")
+    private Integer asyncIoThreadCount;
+
+    @Value("${http.syncConnectTimeout}")
+    private Integer syncConnectTimeout;
+
+    @Value("${http.syncSocketTimeout}")
+    private Integer syncSocketTimeout;
+
+    @Value("${http.syncConnectionRequestTimeout}")
+    private Integer syncConnectionRequestTimeout;
+
+    @Value("${http.syncConnectPerRoute}")
+    private Integer syncConnectPerRoute;
+
+    @Value("${http.syncConnectNum}")
+    private Integer syncConnectNum;
+
+    private RequestConfig asyncRequestConfig;
+
+    private PoolingNHttpClientConnectionManager asyncConnManager;
+
+    private RequestConfig syncRequestConfig;
+
+    private PoolingHttpClientConnectionManager syncConnManager;
+
+    private HttpRequestRetryHandler httpRequestRetryHandler;
+
+    @PostConstruct
+    public void init() {
+        asyncRequestConfig = RequestConfig.custom()
+                .setConnectionRequestTimeout(asyncConnectionRequestTimeout)
+                .setConnectTimeout(asyncConnectTimeout)
+                .setSocketTimeout(asyncSocketTimeout)
+                .build();
+        //配置io线程
+        IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
+                .setIoThreadCount(asyncIoThreadCount)
+                .setSoKeepAlive(true)
+                .build();
+
+        ConnectingIOReactor ioReactor = null;
+        try {
+            ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
+        } catch (IOReactorException e) {
+            logger.error("配置 io 线程失败,error:{}", e.getMessage());
+            e.printStackTrace();
+        }
+
+        asyncConnManager = new PoolingNHttpClientConnectionManager(ioReactor);
+        asyncConnManager.setMaxTotal(asyncConnectNum);
+        asyncConnManager.setDefaultMaxPerRoute(asyncConnectPerRoute);
+
+
+
+        syncRequestConfig = RequestConfig.custom()
+                .setConnectionRequestTimeout(syncConnectionRequestTimeout)
+                .setConnectTimeout(syncConnectTimeout)
+                .setSocketTimeout(syncSocketTimeout)
+                .build();
+
+        syncConnManager = new PoolingHttpClientConnectionManager();
+        syncConnManager.setDefaultMaxPerRoute(syncConnectPerRoute);
+        syncConnManager.setMaxTotal(syncConnectNum);
+
+
+
+        // 请求重试处理
+        httpRequestRetryHandler = new HttpRequestRetryHandler() {
+            public boolean retryRequest(IOException exception,
+                                        int executionCount, HttpContext context) {
+                logger.info("http request occurs error:{}", exception.getMessage());
+                if (executionCount >= 20000) {// 如果已经重试了3000次,就放弃
+                    return false;
+                }
+                if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
+                    return false;
+                }
+                if (exception instanceof SSLException) {// SSL握手异常
+                    return false;
+                }
+
+                if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试
+                    return true;
+                }
+                if (exception instanceof InterruptedIOException) {// 超时
+                    return true;
+                }
+                if (exception instanceof SocketException) {
+                    return true;
+                }
+
+                HttpClientContext clientContext = HttpClientContext
+                        .adapt(context);
+                HttpRequest request = clientContext.getRequest();
+                // 如果请求是幂等的,就再次尝试
+                if (!(request instanceof HttpEntityEnclosingRequest)) {
+                    return true;
+                }
+                return true;
+            }
+        };
+
+    }
+
+    /**
+     * 异步 http 连接
+     * @return
+     */
+    public CloseableHttpAsyncClient getHttpAsyncClient() {
+
+        CloseableHttpAsyncClient client = HttpAsyncClients.custom()
+                .setConnectionManager(asyncConnManager)
+                .setDefaultRequestConfig(asyncRequestConfig)
+                .build();
+        return client;
+    }
+
+    /**
+     * 同步 http 连接
+     * @return
+     */
+    public CloseableHttpClient getHttpSyncClient() {
+        CloseableHttpClient httpClient = HttpClients.custom()
+                .setConnectionManager(syncConnManager)
+                .setDefaultRequestConfig(syncRequestConfig)
+                .setRetryHandler(httpRequestRetryHandler)
+                .build();
+        return httpClient;
+    }
+
+}

+ 127 - 52
src/main/java/com/uas/ps/inquiry/util/HttpUtil.java

@@ -1,21 +1,23 @@
 package com.uas.ps.inquiry.util;
 
+import com.uas.ps.core.util.ContextUtils;
+import com.uas.ps.inquiry.http.HttpAsyncCallback;
+import com.uas.ps.inquiry.http.HttpClientSpringFactory;
 import org.apache.http.Consts;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.methods.*;
+import org.apache.http.concurrent.FutureCallback;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.entity.mime.content.FileBody;
 import org.apache.http.entity.mime.content.StringBody;
 import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.protocol.HTTP;
 import org.apache.http.util.EntityUtils;
@@ -44,6 +46,85 @@ import java.util.Set;
  */
 public class HttpUtil {
 
+	private static HttpClientSpringFactory clientSpringFactory;
+
+	private static HttpAsyncCallback httpAsyncCallback;
+
+	static {
+		clientSpringFactory = ContextUtils.getBean(HttpClientSpringFactory.class);
+		httpAsyncCallback = ContextUtils.getBean(HttpAsyncCallback.class);
+	}
+
+	/**
+	 * 异步 get 请求,使用默认callback
+	 * @param url
+	 * @param params
+	 */
+	public static void doGetAsync(String url, Map<String, ?> params) {
+		doGetAsync(url, params, false, httpAsyncCallback);
+	}
+
+	/**
+	 * 异步 get 请求,使用自定义callback
+	 * @param url
+	 * @param params
+	 */
+	public static void doGetAsync(String url, Map<String, ?> params, FutureCallback<HttpResponse> callback) {
+		doGetAsync(url, params, false, callback);
+	}
+
+	public static void doGetAsync(String url, Map<String, ?> params, boolean sign, FutureCallback<HttpResponse> callback) {
+		HttpGet httpGet = null;
+		try {
+			httpGet = new HttpGet(getRequestUrl(url, (Map<String, Object>) params, sign));
+			CloseableHttpAsyncClient httpAsyncClient = clientSpringFactory.getHttpAsyncClient();
+			httpAsyncClient.start();
+			httpAsyncClient.execute(httpGet, callback);
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			if (httpGet != null) {
+				httpGet.releaseConnection();
+			}
+		}
+
+	}
+
+	/**
+	 * 异步 post 请求,默认使用 HttpAsyncCallback 回调
+	 * @param postUrl
+	 * @param formData
+	 */
+	public static void doPostAsync(String postUrl, String formData) {
+
+		doPostAsync(postUrl, formData, httpAsyncCallback);
+	}
+
+	/**
+	 * 异步 post 请求,自定义回调
+	 * @param postUrl
+	 * @param formData
+	 */
+	public static void doPostAsync(String postUrl, String formData, FutureCallback<HttpResponse> callback) {
+
+		HttpPost post = null;
+		try {
+			CloseableHttpAsyncClient httpAsyncClient = clientSpringFactory.getHttpAsyncClient();
+			httpAsyncClient.start();
+			post = new HttpPost(postUrl);
+			StringEntity postingString = new StringEntity(formData,  HTTP.UTF_8);
+			post.setEntity(postingString);
+			post.setHeader("Content-type", "application/json");
+			httpAsyncClient.execute(post, callback);
+
+		} finally {
+			if (post != null) {
+				post.releaseConnection();
+			}
+		}
+	}
+
+
 	/**
 	 * 发送GET请求
 	 *
@@ -175,14 +256,23 @@ public class HttpUtil {
 	 * @throws Exception
 	 */
 	public static String doPost(String postUrl, String formData) throws Exception {
-		HttpClient httpClient = new DefaultHttpClient();
-		HttpPost post = new HttpPost(postUrl);
-		StringEntity postingString = new StringEntity(formData,  HTTP.UTF_8);
-		post.setEntity(postingString);
-		post.setHeader("Content-type", "application/json");
-		HttpResponse response = httpClient.execute(post);
-		String content = EntityUtils.toString(response.getEntity());
-		return content;
+		HttpPost post = null;
+		try {
+			CloseableHttpClient httpClient = clientSpringFactory.getHttpSyncClient();
+			post = new HttpPost(postUrl);
+			StringEntity postingString = new StringEntity(formData,  HTTP.UTF_8);
+			post.setEntity(postingString);
+			post.setHeader("Content-type", "application/json");
+			HttpResponse response = httpClient.execute(post);
+			String content = EntityUtils.toString(response.getEntity());
+			return content;
+		} finally {
+			if (post != null) {
+				post.releaseConnection();
+			}
+		}
+
+
 	}
 
 	/**
@@ -251,21 +341,14 @@ public class HttpUtil {
 	 * @throws Exception
 	 */
 	public static Response sendHttpUriRequest(HttpRequestBase request) throws Exception {
-		CloseableHttpClient httpClient = HttpClients.createDefault();
+		CloseableHttpClient httpClient = clientSpringFactory.getHttpSyncClient();
 		CloseableHttpResponse response = null;
 		try {
 			response = httpClient.execute(request);
 			return Response.getResponse(response);
 		} finally {
-			try {
-				httpClient.close();
-			} catch (IOException e) {
-			}
-			if (response != null) {
-				try {
-					response.close();
-				} catch (IOException e) {
-				}
+			if (request != null) {
+				request.releaseConnection();
 			}
 		}
 	}
@@ -280,7 +363,7 @@ public class HttpUtil {
 	 */
 	public static Response sendHttpEntityEnclosingRequest(HttpEntityEnclosingRequestBase request,
 														  Map<String, Object> params, boolean encode) throws Exception {
-		CloseableHttpClient httpClient = HttpClients.createDefault();
+		CloseableHttpClient httpClient = clientSpringFactory.getHttpSyncClient();
 		CloseableHttpResponse response = null;
 		try {
 			if (!encode) {
@@ -305,16 +388,8 @@ public class HttpUtil {
 			response = httpClient.execute(request);
 			return Response.getResponse(response);
 		} finally {
-			request.releaseConnection();
-			try {
-				httpClient.close();
-			} catch (IOException e) {
-			}
-			if (response != null) {
-				try {
-					response.close();
-				} catch (IOException e) {
-				}
+			if (request != null) {
+				request.releaseConnection();
 			}
 		}
 	}
@@ -460,11 +535,13 @@ public class HttpUtil {
 	 */
 	public static Response upload(String postUrl, String filePath, Map<String, String> params)
 			throws IllegalStateException, IOException, Exception {
-		CloseableHttpClient httpClient = null;
+
+		CloseableHttpClient httpClient = clientSpringFactory.getHttpSyncClient();
 		CloseableHttpResponse response = null;
+		HttpPost httpPost = null;
 		try {
-			httpClient = HttpClients.createDefault();
-			HttpPost httpPost = new HttpPost(postUrl);
+
+			httpPost = new HttpPost(postUrl);
 			FileBody fileBody = new FileBody(new File(filePath));
 			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
 			builder.addPart("file", fileBody);
@@ -479,20 +556,10 @@ public class HttpUtil {
 			httpPost.setEntity(reqEntity);
 			response = httpClient.execute(httpPost);
 		} finally {
-			try {
-				if (response != null) {
-					response.close();
-				}
-			} catch (IOException e) {
-				e.printStackTrace();
-			}
-			try {
-				if (httpClient != null) {
-					httpClient.close();
-				}
-			} catch (IOException e) {
-				e.printStackTrace();
+			if (httpPost != null) {
+				httpPost.releaseConnection();
 			}
+
 		}
 		return Response.getResponse(response);
 	}
@@ -506,10 +573,18 @@ public class HttpUtil {
 	 * @throws IOException
 	 */
 	public static InputStream download(String postUrl) throws ClientProtocolException, IOException {
-		CloseableHttpClient httpClient = HttpClients.createDefault();
-		HttpGet httpGet = new HttpGet(postUrl);
-		CloseableHttpResponse response = httpClient.execute(httpGet);
-		return response.getEntity().getContent();
+		HttpGet httpGet = null;
+		try {
+			CloseableHttpClient httpClient = clientSpringFactory.getHttpSyncClient();
+			httpGet = new HttpGet(postUrl);
+			CloseableHttpResponse response = httpClient.execute(httpGet);
+			return response.getEntity().getContent();
+		} finally {
+			if (httpGet != null) {
+				httpGet.releaseConnection();
+			}
+		}
+
 	}
 
 	/**

+ 12 - 0
src/main/resources/config/application-cloud.properties

@@ -26,6 +26,18 @@ mall.url = http://10.10.0.10
 message.senderuu=1000010022
 message.senderEnuu=10042875
 
+http.asyncConnectTimeout=30000
+http.asyncSocketTimeout=30000
+http.asyncConnectionRequestTimeout=10000
+http.asyncConnectNum=500
+http.asyncConnectPerRoute=10
+http.asyncIoThreadCount=500
+http.syncConnectTimeout=60000
+http.syncSocketTimeout=60000
+http.syncConnectionRequestTimeout=10000
+http.syncConnectPerRoute=10
+http.syncConnectNum=500
+
 
 server.tomcat.max-connections=10000
 server.tomcat.max-threads=200

+ 12 - 0
src/main/resources/config/application-dev.properties

@@ -29,6 +29,18 @@ mall.url = http://192.168.253.12:23400/
 message.senderuu=1000010022
 message.senderEnuu=10043516
 
+http.asyncConnectTimeout=30000
+http.asyncSocketTimeout=30000
+http.asyncConnectionRequestTimeout=10000
+http.asyncConnectNum=500
+http.asyncConnectPerRoute=10
+http.asyncIoThreadCount=500
+http.syncConnectTimeout=60000
+http.syncSocketTimeout=60000
+http.syncConnectionRequestTimeout=10000
+http.syncConnectPerRoute=10
+http.syncConnectNum=500
+
 
 server.tomcat.max-connections=10000
 server.tomcat.max-threads=200

+ 12 - 0
src/main/resources/config/application-test.properties

@@ -26,6 +26,18 @@ mall.url = http://192.168.253.12:23400/
 message.senderuu=1000010022
 message.senderEnuu=10043516
 
+http.asyncConnectTimeout=30000
+http.asyncSocketTimeout=30000
+http.asyncConnectionRequestTimeout=10000
+http.asyncConnectNum=500
+http.asyncConnectPerRoute=10
+http.asyncIoThreadCount=500
+http.syncConnectTimeout=60000
+http.syncSocketTimeout=60000
+http.syncConnectionRequestTimeout=10000
+http.syncConnectPerRoute=10
+http.syncConnectNum=500
+
 
 server.tomcat.max-connections=10000
 server.tomcat.max-threads=200

+ 12 - 0
src/main/resources/config/application-txcloud.properties

@@ -27,6 +27,18 @@ mall.url = http://172.16.0.100
 message.senderuu=1000010022
 message.senderEnuu=10042875
 
+http.asyncConnectTimeout=30000
+http.asyncSocketTimeout=30000
+http.asyncConnectionRequestTimeout=10000
+http.asyncConnectNum=500
+http.asyncConnectPerRoute=10
+http.asyncIoThreadCount=500
+http.syncConnectTimeout=60000
+http.syncSocketTimeout=60000
+http.syncConnectionRequestTimeout=10000
+http.syncConnectPerRoute=10
+http.syncConnectNum=500
+
 
 server.tomcat.max-connections=10000
 server.tomcat.max-threads=200