• httpclient4.5 连接池的封装


    随着微服务的流行,服务之间的http调用越来越多,遇到的问题也比较多,写这边文章的目的也是将自己遇到的坑和解决方案跟大家分享

    一、为什么要用Http连接池

    1、降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗,别小看这几次握手,本人经过测试发现,基本上3倍的时间延迟

    2、支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接

    二、代码

    1、PoolingHttpClientFactory.java连接池管理类,支持http与https协议

    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.config.RequestConfig.Builder;
    import org.apache.http.config.Registry;
    import org.apache.http.config.RegistryBuilder;
    import org.apache.http.conn.socket.ConnectionSocketFactory;
    import org.apache.http.conn.socket.PlainConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    
    public class PoolingHttpClientFactory {
        private int timeOut = 30000;
        private int maxConnectionTotal = 400;
        private int maxConnectionPerRoute = 400;
        private PoolingHttpClientConnectionManager poolConnManager;
        private Builder builder;
        private RequestConfig requestConfig;
        private HttpClientBuilder hcb;
    
        private static PoolingHttpClientFactory pooling = new PoolingHttpClientFactory();
    
        private PoolingHttpClientFactory() {
            poolConnManager = createConnectionManager();
            builder = RequestConfig.custom();
            if(timeOut != 0){
                builder.setConnectionRequestTimeout(timeOut).setConnectTimeout(timeOut).setSocketTimeout(timeOut);
            }
            requestConfig = builder.build();
            hcb = HttpClients.custom().setConnectionManager(poolConnManager).setDefaultRequestConfig(requestConfig);
        }
    
        public static PoolingHttpClientFactory getInstance() {
            if (pooling == null) {
                pooling = new PoolingHttpClientFactory();
            }
            return pooling;
        }
    
        public CloseableHttpClient createHttpClient(){
            CloseableHttpClient httpClient = hcb.build();
            return httpClient;
        }
    
        public PoolingHttpClientConnectionManager createConnectionManager(){
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", SSLConnectionSocketFactory.getSocketFactory())
                    .build();
    
            PoolingHttpClientConnectionManager poolConnManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            if(maxConnectionTotal != 0){
                poolConnManager.setMaxTotal(maxConnectionTotal);
            }
            if(maxConnectionPerRoute != 0){
                poolConnManager.setDefaultMaxPerRoute(maxConnectionPerRoute);
            }
            return poolConnManager;
        }
    
        public void setTimeOut(int timeOut) {
            this.timeOut = timeOut;
        }
        public void setMaxConnectionTotal(int maxConnectionTotal) {
            this.maxConnectionTotal = maxConnectionTotal;
        }
        public void setMaxConnectionPerRoute(int maxConnectionPerRoute) {
            this.maxConnectionPerRoute = maxConnectionPerRoute;
        }
    }

    2、连接池消费类:TestClient.java

    import com.alibaba.fastjson.JSON;
    import org.apache.commons.io.IOUtils;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.testng.annotations.Test;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class TestClient {
        PoolingHttpClientFactory connManager;
    
        public Object get(String path){
            CloseableHttpClient httpClient = PoolingHttpClientFactory.getInstance().createHttpClient(); //创建实例对象
            HttpGet httpget = new HttpGet(path);
            String json=null;
            CloseableHttpResponse response=null;
            try {
                response = httpClient.execute(httpget);
                InputStream in=response.getEntity().getContent();
                json= IOUtils.toString(in, "Utf8");
                in.close();
            } catch (UnsupportedOperationException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(response!=null){
                    try {
                        response.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return JSON.parse(json);
        }
        public Object post(String path){
            CloseableHttpClient httpClient = PoolingHttpClientFactory.getInstance().createHttpClient(); //创建实例对象
            HttpPost httppost = new HttpPost(path);
            String json=null;
            CloseableHttpResponse response=null;
            try {
                response = httpClient.execute(httppost);
                InputStream in=response.getEntity().getContent();
                json= IOUtils.toString(in, "Utf8");
                in.close();
            } catch (UnsupportedOperationException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(response!=null){
                    try {
                        response.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return JSON.parse(json);
        }

    三、原理及注意事项

    连接池中连接都是在发起请求的时候建立,并且都是长连接

    TestClient.java中的in.close();作用就是将用完的连接释放,下次请求可以复用,这里特别注意的是,如果不使用in.close();而仅仅使用response.close();结果就是连接会被关闭,并且不能被复用,这样就失去了采用连接池的意义。

    连接池释放连接的时候,并不会直接对TCP连接的状态有任何改变,只是维护了两个Set,leased和avaliabled,leased代表被占用的连接集合,avaliabled代表可用的连接的集合,释放连接的时候仅仅是将连接从leased中remove掉了,并把连接放到avaliabled集合中

  • 相关阅读:
    服务器负载均衡的基本功能和实现原理
    几种负载均衡技术的实现
    Postman-CI集成Jenkins
    Postman-进阶
    Postman-简单使用
    chrome安装插件,安装Postman
    关于angularjs dom渲染结束再执行的问题
    Protractor(angular定制的e2e)的简易入门
    关于ng-router嵌套使用和总结
    scss使用后的简单入门总结
  • 原文地址:https://www.cnblogs.com/unknows/p/8604658.html
Copyright © 2020-2023  润新知