Apache HttpClient 使用(下)

4. 链接池

通常我们可以使用PoolingHttpClientConnectionManager来创建一个链接池。

4.1 对于链接池的管理

1
2
3
4
5
6
7
8
9
10
11
12
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();  
// 设置最大连接数
cm.setMaxTotal(200);
// 设置每个主机地址的并发数
cm.setDefaultMaxPerRoute(20);
// 通过PoolingHttpClientConnectionManager,来获取CloseableHttpClient
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();

// 创建http GET请求
HttpGet httpGet = new HttpGet("http://www.baidu.com/");
// 执行请求
response = httpClient.execute(httpGet);

4.2 关闭链接池中失效的链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import org.apache.http.conn.HttpClientConnectionManager;  
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

//关闭连接池的无效链接
public class ClientEvictExpiredConnections {

public static void main(String[] args) throws Exception {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// 设置最大连接数
cm.setMaxTotal(200);
// 设置每个主机地址的并发数
cm.setDefaultMaxPerRoute(20);
// 开启线程用于关闭失效的链接
new IdleConnectionEvictor(cm).start();
}

public static class IdleConnectionEvictor extends Thread {
private final HttpClientConnectionManager connMgr;
private volatile boolean shutdown;

public IdleConnectionEvictor(HttpClientConnectionManager connMgr) {
this.connMgr = connMgr;
}

@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000); // 每隔5秒执行一个,关闭失效的http连接
connMgr.closeExpiredConnections(); // 关闭失效链接
connMgr.closeIdleConnections(30, TimeUnit.SECONDS); // 关闭空闲链接
}
}
} catch (InterruptedException ex) {
// 结束
shutdown();
}
}

public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}
}

4.4 关闭

一个连接可以优雅的关闭:清空发送缓冲区然后再进行关闭。也可以强制关闭,通过调用shutdown方法,此时发送缓冲区不会被清空。
要关闭一个机遇Pooling的HttpClient,按照下面的步骤:

  • 消费并关闭返回的response对象
  • 关闭HttpClient
  • 关闭Connection Manager

例如:

1
2
3
4
5
6
7
8
9
connManager = new PoolingHttpClientConnectionManager();
CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
HttpGet get = new HttpGet("http://google.com");
CloseableHttpResponse response = client.execute(get);

EntityUtils.consume(response.getEntity());
response.close();
client.close();
connManager.close(); // 关闭链接池

如果直接关闭connManager,那所有相关的链接都会被关闭,资源也会被释放,但是发送缓冲区不会被清空(flush)

5. 访问双向SSL保护的资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public static HttpClientConnectionManager CONNECTION_MANAGER = null;

public void init(String keyStoreFile, String keyStorePass,
String trustStoreFile, String trustStorePass) throws Exception {
System.out.println("init conection pool...");

InputStream ksis = new FileInputStream(new File(keyStoreFile));
InputStream tsis = new FileInputStream(new File(trustStoreFile));

KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(ksis, keyStorePass.toCharArray());

KeyStore ts = KeyStore.getInstance("JKS");
ts.load(tsis, trustStorePass.toCharArray());

// init SSLContext with keystore, truststore
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(ks, keyStorePass.toCharArray())
.loadTrustMaterial(ts, new TrustSelfSignedStrategy()).build();

// init SSLConnectionSocketFactory
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
new String[] { "TLSv1" },
null,
NoopHostnameVerifier.INSTANCE); // not check common name

Registry<ConnectionSocketFactory> registry = RegistryBuilder
.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", sslsf).build();
ksis.close();
tsis.close();
CONNECTION_MANAGER = new PoolingHttpClientConnectionManager(registry);
}

public String doPost(String url, String params) throws Exception {
if (CONNECTION_MANAGER == null) {
return null;
}
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(CONNECTION_MANAGER).build();
HttpPost httpPost = new HttpPost(url);

httpPost.setEntity(new StringEntity(params,
ContentType.APPLICATION_JSON));

CloseableHttpResponse resp = httpClient.execute(httpPost);
System.out.println(resp.getStatusLine());
InputStream respIs = resp.getEntity().getContent();
String content = convertStreamToString(respIs);
EntityUtils.consume(resp.getEntity());
return content;
}

// Get data from InputStream
public static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();

String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}

上面的代码首先创建了一个PoolingHttpClientConnectionManager,然后定义了sendPost方法,可以用来发送Post请求。

附录、参考资料

热评文章