new DefaultHttpClient过时处理建议和HTTP调用后关闭流处理

来源:互联网 发布:java单例 编辑:程序博客网 时间:2024/06/14 08:38

最近写新的调用代码时候,发现项目中new DefaultHttpClient()实例过期很久了,翻了翻另一个生产项目调用端的代码也是如此,于是查阅了些资料,用新版本代码替换了手上项目的代码并且正常测试完、生产上也正常运行完,算是一次补习,特记录下替换过程和调用完后的处理。

1:来看下原来的调用代码,也是最常用的(httpclient版本超过4.2.6):(仅限于引用org.apache.httpcomponents的调用方式)

  项目原先用的4.3.1,过了4.2.6就已经过时了,过时代码下面我会标注。  

复制代码
       HttpClient httpclient = new DefaultHttpClient();        HttpPost httppost = new HttpPost("调用地址");        List<NameValuePair> formparams = new ArrayList<NameValuePair>();        formparams.add(new BasicNameValuePair("参数队列头部", 调用参数));        System.out.println("==== 提交参数 ======" +formparams);        UrlEncodedFormEntity uefEntity;        try {            uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");            httppost.setEntity(uefEntity);            HttpResponse response = httpclient.execute(httppost);            HttpEntity entity = response.getEntity();            if(entity!=null){                String results=EntityUtils.toString(entity, "UTF-8");                System.out.println("接口返回值="+results);            }         EntityUtils.consume(entity);        } catch (ClientProtocolException e) {            e.printStackTrace();        } catch (UnsupportedEncodingException e1) {            e1.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } finally {            // 关闭连接,释放资源            httpclient.getConnectionManager().shutdown();        }
复制代码

  

  从4.2.6版本后,原作用类就出现了过时标识注明,看了maven仓更新时间2013-09-04是4.2.6和4.3同时发布的。

 

2:下面看下DefaultHttpClient的源码:(追溯源码)

 

复制代码
 * @since 4.0  *  * @deprecated (4.3) use {@link HttpClientBuilder}.  */ @ThreadSafe @Deprecated public class DefaultHttpClient extends AbstractHttpClient {      /**      * Creates a new HTTP client from parameters and a connection manager.      *      * @param params    the parameters      * @param conman    the connection manager      */     public DefaultHttpClient(             final ClientConnectionManager conman,             final HttpParams params) {         super(conman, params);     }
复制代码

  看得出来为什么过时了还能用,DefaultHttpClient 继承了 AbstractHttpClient,AbstractHttpClient 继承了CloseableHttpClient。

  ”Creates a new HTTP client from parameters and a connection manager“ ,创建一个HTTP管理连接的一个”动作“类。

  ”* @deprecated (4.3) use {@link HttpClientBuilder}.“ ,说明从4.3版本后使用httpclientBuilder新的类,类httpclientBuilder的头部介绍:

  ”* Please note that some settings used by this class can be mutually exclusive and may not apply when building {@link CloseableHttpClient}“,翻译过来是和CloseableHttpClient有互斥性,看到有hostname,ssl安全证书加载这些就知道是中后期才会运行到的,都是在外部封装类运行提交的参数后内部运行的。

  

  这是调式模式下,图中可以看到参数会传递到httpClientBuilder中处理。

  

  综合资料和httpClientBuilder的作用写下新的调用代码(HttpClientBuilder里CloseableHttpClient的build方法):

复制代码
private static final CloseableHttpClient httpClient;    static {        RequestConfig config = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(15000).build();        httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();    }    public static void TestHttpPost(String url, String jsonData) {        HttpPost httpPost = new HttpPost("调用地址");        // 拼接参数        List<NameValuePair> list = new ArrayList<NameValuePair>();        list.add(new BasicNameValuePair("参数队列头部", 调用参数));        System.out.println("==== 提交参数 ======" + list);        CloseableHttpResponse response = null;        try {            httpPost.setEntity(new UrlEncodedFormEntity(list));            response = httpClient.execute(httpPost);            int statusCode = response.getStatusLine().getStatusCode();            if (statusCode != HttpStatus.SC_OK) {                httpPost.abort();                throw new RuntimeException("HttpClient,error status code :" + statusCode);            }            System.out.println("========HttpResponseProxy:========" + statusCode);            HttpEntity entity = response.getEntity();            if (entity != null) {                String result = EntityUtils.toString(entity, "UTF-8");                System.out.println("========接口返回=======" + result);            }            EntityUtils.consume(entity);        } catch (Exception e) {            e.printStackTrace();        } finally {            if (response != null) {                try {                    response.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if (httpClient != null) {                try {                    httpClient.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    } 
复制代码

 

  看AbstractHttpClient 继承了CloseableHttpClient的CloseableHttpClient:

  @ThreadSafe //线程安全
  public abstract class CloseableHttpClient implements HttpClient, Closeable

  不难看出实现了httpclient,那么调用方法有了,还实现了关闭流,说明调用完毕后会做关闭处理。CloseableHttpResponse也替换了原来的HttpResponse ,使用CloseableHttpClient的新版本代码:

 

复制代码
        CloseableHttpClient httpClient = HttpClients.createDefault();        HttpPost httpPost = new HttpPost(”调用地址“);                //拼接参数        List<NameValuePair> list = new ArrayList<NameValuePair>();        list.add(new BasicNameValuePair("参数队列头部", 调用参数));        System.out.println("==== 提交参数 ======" +list);        CloseableHttpResponse response  = null;        try {            httpPost.setEntity(new UrlEncodedFormEntity(list));            response = httpClient.execute(httpPost);            System.out.println("========HttpResponseProxy:========"+response.getStatusLine());            HttpEntity entity = response.getEntity();            if(entity != null){                String result = EntityUtils.toString(entity, "UTF-8");                System.out.println("========接口返回=======" +result);            }            EntityUtils.consume(entity);            //httpClient.getConnectionManager().shutdown();        } catch (Exception e) {            e.printStackTrace();        }finally {            if(response != null){                try {                    response.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if(httpClient != null){                try {                    httpClient.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }
复制代码

 

   

3:旧版本调用完处理和新版本调用完处理:

  先看旧版本的关闭方法,

  httpclient.getConnectionManager().shutdown();

  只要httpclient开启后,BasicClientConnectionManager里的托管连接connManager初始化,其中shutdown开启 = false,运行完调用shutdown方法变 = true。

  Response接收httpEntity返回参数时,EntityUtils.consume(entity);关闭参数流操作。

  总结:连接动作关闭,接收参数流关闭。

复制代码
public static void consume(final HttpEntity entity) throws IOException {        if (entity == null) {            return;        }        if (entity.isStreaming()) {            final InputStream instream = entity.getContent();            if (instream != null) {                instream.close();            }        }    }
复制代码

 

  新方法调用后关闭方法,

  httpClient.close();

  新方法是开启了CloseableHttpClient后,PoolingHttpClientConnectionManager赋值CloseableHttpClient 对象并初始化,shutdown为开启状态。

  httpClient.getConnectionManager().shutdown(); 和 httpClient.close(); 都是关闭调用功能,因为实现类都impl实现了Closeable关闭流操作,所以在client端调用哪个方法都是可以关闭的,只是有些方法被注明过时了,用新方法不用担心出现@Deprecated标记。

 

4:总结:

  因为每次调用的不同,不及时关闭在大请求量下就需要谨慎设计代码的安全性了。

原创粉丝点击