HttpClient连接池使用及问题处理

一、问题分析

         系统应用使用Httpclient4.5连接池通过PoolingHttpClientConnectionManager实现,系统运行一段时间后就会出现连接池满的情况,导致无法从连接池中获取到可以使用的httpclient链接,导致服务中断。

在这里插入图片描述

 

源代码如下:

public static synchronized CloseableHttpClient getHttpClient(){
   if(httpClient == null) {
      //注册访问协议相关的Socket工厂
      Registry<ConnectionSocketFactory> socketFactoryRegistry =
            RegistryBuilder.<ConnectionSocketFactory>create()
                  .register("http", PlainConnectionSocketFactory.INSTANCE)
                  .register("https", SSLConnectionSocketFactory.getSystemSocketFactory())
                  .build();

      //HttpConnection工厂:配置写请求/解析响应处理器
      HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection>
            connFactory = new ManagedHttpClientConnectionFactory(
            DefaultHttpRequestWriterFactory.INSTANCE,
            DefaultHttpResponseParserFactory.INSTANCE);
      //DNS解析器
      DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;
      //创建池化连接管理器
      manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry,connFactory,dnsResolver);

      //默认为Socket配置
      SocketConfig defaultSocketConfig = SocketConfig.custom()
            .setTcpNoDelay(true).build();
      manager.setDefaultSocketConfig(defaultSocketConfig);
      //设置连接池的最大连接数
      manager.setMaxTotal(maxTotal);
      //每个路由最大连接数
      manager.setDefaultMaxPerRoute(maxPerRoute);
      //在从连接池获取连接时,连接不活跃多长时间后需要进行一次验证,默认为2s
      manager.setValidateAfterInactivity(validateAfterInactivity * 1000);

      RequestConfig defaultRequestConfig = RequestConfig.custom()
            .setConnectTimeout(connectTimeout * 1000)    //设置连接超时时间,2s
            .setSocketTimeout(socketTimeout * 1000)     //设置等待数据超时时间,5s
            .setConnectionRequestTimeout(connectionRequestTimeout)  //设置从连接池获取连接的等待超时时间
            .build();

      //创建HttpClient
      httpClient = HttpClients.custom()
            .setConnectionManager(manager)
            .setConnectionManagerShared(false)  //连接池不是共享模式
            .evictIdleConnections(60, TimeUnit.SECONDS)  //定期回收空闲连接
            .evictExpiredConnections()  //定期回收过期连接
            .setConnectionTimeToLive(60,TimeUnit.SECONDS)   //连接存活时间,如果不设置,则根据长连接信息决定
            .setDefaultRequestConfig(defaultRequestConfig)  //设置默认请求配置
            .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)    //连接重用策略,即是否能keepAlive
            .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)  //长连接配置,即获取长连接生产多长时间
            .setRetryHandler(new DefaultHttpRequestRetryHandler(0,false))
            //设置重试次数,默认是3次;当前是禁用掉
            .build();

      //JVM停止或重启时,关闭连接池释放掉连接
      Runtime.getRuntime().addShutdownHook(new Thread(){
         @Override
         public void run(){
            try{
               httpClient.close();
            }catch (IOException e){
               e.printStackTrace();
            }
         }
      });
   }
   return httpClient;
}

二、解决方案  

   public static String readNet (String urlPath)  
        {  
            StringBuffer sb = new StringBuffer ();  
            HttpClient client = null;  
            InputStream in = null;  
            InputStreamReader isr = null;  
            HttpGet get = new HttpGet();  
            try  
            {  
                client = HttpConnectionManager.getHttpClient();  
                get.setURI(new URI(urlPath));  
                HttpResponse response = client.execute(get);  
                if (response.getStatusLine ().getStatusCode () != 200) {  
                    get.abort();  
                    return null;  
                }  
                HttpEntity entity =response.getEntity();  
                  
                if( entity != null ){  
                    in = entity.getContent();  
                    ......  
                }  
                return sb.toString ();  
                  
            }  
            catch (Exception e)  
            {  
                get.abort();  
                e.printStackTrace ();  
                return null;  
            }  
            finally  
            {  
                if (isr != null){  
                    try  
                    {  
                        isr.close ();  
                    }  
                    catch (IOException e)  
                    {  
                        e.printStackTrace ();  
                    }  
                }  
                if (in != null){  
                    try  
                    {  
                        in.close ();  
                    }  
                    catch (IOException e)  
                    {  
                        e.printStackTrace ();  
                    }  
                }  
            }  
        }

 

显示调用HttpGet的abort,这样就会直接中止这次连接,我们在遇到异常的时候应该显示调用,因为谁能保证异常是在InputStream in赋值之后才抛出的呢。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值