4. 链接池
通常我们可以使用PoolingHttpClientConnectionManager
来创建一个链接池。
4.1 对于链接池的管理
1PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
2// 设置最大连接数
3cm.setMaxTotal(200);
4// 设置每个主机地址的并发数
5cm.setDefaultMaxPerRoute(20);
6// 通过PoolingHttpClientConnectionManager,来获取CloseableHttpClient
7CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
8
9// 创建http GET请求
10HttpGet httpGet = new HttpGet("http://www.baidu.com/");
11// 执行请求
12response = httpClient.execute(httpGet);
4.2 关闭链接池中失效的链接
1import org.apache.http.conn.HttpClientConnectionManager;
2import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
3
4//关闭连接池的无效链接
5public class ClientEvictExpiredConnections {
6
7 public static void main(String[] args) throws Exception {
8 PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
9 // 设置最大连接数
10 cm.setMaxTotal(200);
11 // 设置每个主机地址的并发数
12 cm.setDefaultMaxPerRoute(20);
13 // 开启线程用于关闭失效的链接
14 new IdleConnectionEvictor(cm).start();
15 }
16
17 public static class IdleConnectionEvictor extends Thread {
18 private final HttpClientConnectionManager connMgr;
19 private volatile boolean shutdown;
20
21 public IdleConnectionEvictor(HttpClientConnectionManager connMgr) {
22 this.connMgr = connMgr;
23 }
24
25 @Override
26 public void run() {
27 try {
28 while (!shutdown) {
29 synchronized (this) {
30 wait(5000); // 每隔5秒执行一个,关闭失效的http连接
31 connMgr.closeExpiredConnections(); // 关闭失效链接
32 connMgr.closeIdleConnections(30, TimeUnit.SECONDS); // 关闭空闲链接
33 }
34 }
35 } catch (InterruptedException ex) {
36 // 结束
37 shutdown();
38 }
39 }
40
41 public void shutdown() {
42 shutdown = true;
43 synchronized (this) {
44 notifyAll();
45 }
46 }
47 }
48}
4.4 关闭
一个连接可以优雅的关闭:清空发送缓冲区然后再进行关闭。也可以强制关闭,通过调用shutdown方法,此时发送缓冲区不会被清空。 要关闭一个机遇Pooling的HttpClient,按照下面的步骤:
- 消费并关闭返回的response对象
- 关闭HttpClient
- 关闭Connection Manager
例如:
1connManager = new PoolingHttpClientConnectionManager();
2CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
3HttpGet get = new HttpGet("http://google.com");
4CloseableHttpResponse response = client.execute(get);
5
6EntityUtils.consume(response.getEntity());
7response.close();
8client.close();
9connManager.close(); // 关闭链接池
如果直接关闭connManager,那所有相关的链接都会被关闭,资源也会被释放,但是发送缓冲区不会被清空(flush)。
5. 访问双向SSL保护的资源
1 public static HttpClientConnectionManager CONNECTION_MANAGER = null;
2
3 public void init(String keyStoreFile, String keyStorePass,
4 String trustStoreFile, String trustStorePass) throws Exception {
5 System.out.println("init conection pool...");
6
7 InputStream ksis = new FileInputStream(new File(keyStoreFile));
8 InputStream tsis = new FileInputStream(new File(trustStoreFile));
9
10 KeyStore ks = KeyStore.getInstance("PKCS12");
11 ks.load(ksis, keyStorePass.toCharArray());
12
13 KeyStore ts = KeyStore.getInstance("JKS");
14 ts.load(tsis, trustStorePass.toCharArray());
15
16 // init SSLContext with keystore, truststore
17 SSLContext sslContext = SSLContexts.custom()
18 .loadKeyMaterial(ks, keyStorePass.toCharArray())
19 .loadTrustMaterial(ts, new TrustSelfSignedStrategy()).build();
20
21 // init SSLConnectionSocketFactory
22 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
23 new String[] { "TLSv1" },
24 null,
25 NoopHostnameVerifier.INSTANCE); // not check common name
26
27 Registry<ConnectionSocketFactory> registry = RegistryBuilder
28 .<ConnectionSocketFactory> create()
29 .register("http", PlainConnectionSocketFactory.INSTANCE)
30 .register("https", sslsf).build();
31 ksis.close();
32 tsis.close();
33 CONNECTION_MANAGER = new PoolingHttpClientConnectionManager(registry);
34 }
35
36 public String doPost(String url, String params) throws Exception {
37 if (CONNECTION_MANAGER == null) {
38 return null;
39 }
40 CloseableHttpClient httpClient = HttpClients.custom()
41 .setConnectionManager(CONNECTION_MANAGER).build();
42 HttpPost httpPost = new HttpPost(url);
43
44 httpPost.setEntity(new StringEntity(params,
45 ContentType.APPLICATION_JSON));
46
47 CloseableHttpResponse resp = httpClient.execute(httpPost);
48 System.out.println(resp.getStatusLine());
49 InputStream respIs = resp.getEntity().getContent();
50 String content = convertStreamToString(respIs);
51 EntityUtils.consume(resp.getEntity());
52 return content;
53 }
54
55 // Get data from InputStream
56 public static String convertStreamToString(InputStream is) {
57 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
58 StringBuilder sb = new StringBuilder();
59
60 String line = null;
61 try {
62 while ((line = reader.readLine()) != null) {
63 sb.append(line + "\n");
64 }
65 } catch (IOException e) {
66 e.printStackTrace();
67 } finally {
68 try {
69 is.close();
70 } catch (IOException e) {
71 e.printStackTrace();
72 }
73 }
74 return sb.toString();
75 }
上面的代码首先创建了一个PoolingHttpClientConnectionManager,然后定义了sendPost方法,可以用来发送Post请求。