java의 HttpClient를 사용하여 다중 스레드 병렬

설명: 아래의 코드는 httpclient4.5.2를 바탕으로 실현됩니다.
우리는 자바의 HttpClient를 사용하여 get 요청 웹 페이지를 캡처하는 것이 비교적 실현하기 쉬운 작업이다.

  public static String get(String url) {
    CloseableHttpResponseresponse = null;
    BufferedReader in = null;
    String result = "";
    try {
      CloseableHttpClienthttpclient = HttpClients.createDefault();
      HttpGethttpGet = new HttpGet(url);
      response = httpclient.execute(httpGet);
 
      in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
      StringBuffersb = new StringBuffer("");
      String line = "";
      String NL = System.getProperty("line.separator");
      while ((line = in.readLine()) != null) {
        sb.append(line + NL);
      }
      in.close();
      result = sb.toString();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (null != response) response.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return result;
  }
get 요청을 다중 스레드로 실행할 때 위의 방법도 사용할 수 있습니다.그러나 이런 다중 스레드 요청은 get 방법을 호출할 때마다 HttpClient를 만드는 실례를 바탕으로 이루어진다.각 HttpClient 인스턴스는 한 번 사용하면 다시 회수됩니다.이것은 분명히 가장 좋은 실현이 아니다.
HttpClient는 공식 문서의 Pooling connection 관리자를 볼 수 있는 다중 스레드 요청 방안을 제공합니다.Http클라이언트의 다중 스레드 요청은 내장된 연결 탱크를 바탕으로 이루어진다. 그 중에서 관건적인 클래스는 PoolingHttpClientConnectionManager이다. 이 클래스는 HttpClient 연결 탱크를 관리하는 것을 책임진다.PoolingHttpClientConnectionManager에서 두 가지 관건적인 방법을 제공했습니다: setMaxTotal과 setDefaultMaxPerRoute.setMaxTotal은 연결 풀의 최대 연결 수를 설정하고, setDefaultMaxPerRoute는 모든 루트의 기본 연결 개수를 설정합니다.또한 setMaxPerRoute – 특정 사이트에 대한 최대 연결 개수를 단독으로 설정하는 방법도 있습니다.

   HttpHosthost = new HttpHost("locahost", 80);
   cm.setMaxPerRoute(new HttpRoute(host), 50);
문서에 따라 get 요청을 살짝 조정합니다.

package com.zhyea.robin;
 
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class HttpUtil {
 
  private static CloseableHttpClienthttpClient;
 
  static {
    PoolingHttpClientConnectionManagercm = new PoolingHttpClientConnectionManager();
    cm.setMaxTotal(200);
    cm.setDefaultMaxPerRoute(20);
    cm.setDefaultMaxPerRoute(50);
    httpClient = HttpClients.custom().setConnectionManager(cm).build();
  }
 
  public static String get(String url) {
    CloseableHttpResponseresponse = null;
    BufferedReaderin = null;
    String result = "";
    try {
 
      HttpGethttpGet = new HttpGet(url);
      response = httpClient.execute(httpGet);
 
      in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
      StringBuffersb = new StringBuffer("");
      String line = "";
      String NL = System.getProperty("line.separator");
      while ((line = in.readLine()) != null) {
        sb.append(line + NL);
      }
      in.close();
      result = sb.toString();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (null != response) response.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return result;
  }
 
  public static void main(String[] args) {
    System.out.println(get("https://www.baidu.com/"));
  }
}
이렇게 하면 얼마 안 된다.그러나 나 자신에게 있어서 나는 httpclient의fluent 실현을 더욱 좋아한다. 예를 들어 우리가 방금 실현한 httpget 요청은 이렇게 간단하게 실현할 수 있다.

package com.zhyea.robin;
 
import org.apache.http.client.fluent.Request;
import java.io.IOException;
 
public class HttpUtil {
 
  public static String get(String url) {
    String result = "";
    try {
      result = Request.Get(url)
          .connectTimeout(1000)
          .socketTimeout(1000)
          .execute().returnContent().asString();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return result;
  }
 
  public static void main(String[] args) {
    System.out.println(get("https://www.baidu.com/"));
  }
}
우리가 해야 할 일은 이전의 httpclient 의존을 fluent-hc 의존으로 바꾸는 것뿐이다.

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>fluent-hc</artifactId>
   <version>4.5.2</version>
</dependency>
그리고 이 fluent가 천연을 실현하는 것은 Pooling Http Client Connection Manager를 이용하여 완성한 것이다.maxTotal과 defaultMaxPerRoute의 값은 각각 200과 100입니다.

    CONNMGR = new PoolingHttpClientConnectionManager(sfr);
    CONNMGR.setDefaultMaxPerRoute(100);
    CONNMGR.setMaxTotal(200);
유일하게 불쾌한 것은 Executor가 이 두 값을 조정할 방법을 제공하지 않았다는 것이다.하지만 이것도 충분합니다. 정말 안 되면 Executor를 다시 쓰는 방법을 고려하고 Executor를 사용하여 get 요청을 실행할 수 있습니다.

Executor.newInstance().execute(Request.Get(url))
        .returnContent().asString();
이렇게!

좋은 웹페이지 즐겨찾기