http连接池
为什么要用Http连接池
1、降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗。
2、支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接
3、微服务架构的流行,导致了多层级的请求,如果还采用传统的请求方式,效率会大大的降低,小编我就是出于这种原因放弃了传统的方式。改用连接池的方式。
友情提示:
MultiThreadedHttpConnectionManager 在4.5版本中是PoolingHttpClientConnectionManager
伪代码:
- 1.建立连接管理器
- 2.设置连接管理器连接池参数
- 3.将连接管理器交给连接客户端,这样就不用每次关闭socket连接
代码展示:
public class HttpClientUtil { /** * 日志处理类 */ private static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class); // 读取超时 private final static int SOCKET_TIMEOUT = 10000; // 连接超时 private final static int CONNECTION_TIMEOUT = 10000; // 每个HOST的最大连接数量 private final static int MAX_CONN_PRE_HOST = 20; // 连接池的最大连接数 private final static int MAX_CONN = 60; // 连接池 private final static HttpConnectionManager httpConnectionManager; static { httpConnectionManager = new MultiThreadedHttpConnectionManager(); HttpConnectionManagerParams params = httpConnectionManager.getParams(); params.setConnectionTimeout(CONNECTION_TIMEOUT); params.setSoTimeout(SOCKET_TIMEOUT); params.setDefaultMaxConnectionsPerHost(MAX_CONN_PRE_HOST); params.setMaxTotalConnections(MAX_CONN); } /** * 发送主要方法,异常捕获 * * @param httpMethod * @param encoded 编码格式UTF-8 * @return */ public static String doHttpRequest(HttpMethodBase httpMethod, String encoded) { HttpClient httpClient = new HttpClient(httpConnectionManager); resetRequestHeader(httpClient, "10.0.23.178");//伪装ip地址 BufferedReader in = null; String resultString = ""; try { httpClient.executeMethod(httpMethod); in = new BufferedReader(new InputStreamReader(httpMethod .getResponseBodyAsStream(), encoded)); StringBuffer buffer = new StringBuffer(); String line = ""; while ((line = in.readLine()) != null) { buffer.append(line); } resultString = buffer.toString(); } catch (SocketTimeoutException e) { log.error("连接超时" + e.toString()); resultString = returnError("连接超时"); } catch (HttpException e) { log.error("读取外部服务器数据失败" + e.toString()); resultString = returnError("读取外部服务器数据失败"); } catch (UnknownHostException e) { log.error("请求的主机地址无效" + e.toString()); resultString = returnError("请求的主机地址无效"); } catch (IOException e) { log.error("向外部接口发送数据失败" + e.toString()); resultString = returnError("向外部接口发送数据失败"); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } httpMethod.releaseConnection(); } return resultString; } /** * 设置一下返回错误的通用提示,可以自定义格式. * * @param reason * @return */ public static String returnError(String reason) { StringBuffer buffer = new StringBuffer(); buffer.append("<?xml version=\"1.0\" encoding=\"GBK\"?>"); buffer.append("<Response>"); buffer.append("<Success>false</Success>"); buffer.append("<reason>"); buffer.append(reason); buffer.append("</reason>"); buffer.append("</Response>"); return buffer.toString(); } /** *X-Forwarded-For:简称XFF头,它代表代表客户端,也就是HTTP的请求端真实的IP */ public final static String REQUEST_HEADER = "x-forwarded-for"; /** * 将客户IP写入请求头 * 这个设置可以伪装IP请求,注意使用 * * @param client * @param ip * @return */ public static void resetRequestHeader(HttpClient client, String ip) { List<Header> headers = new ArrayList<Header>(); headers.add(new Header(REQUEST_HEADER, ip)); client.getHostConfiguration().getParams().setParameter( "http.default-headers", headers); } }