1.MultiThreadedHttpConnectionManager connectionManager = new MultiThread
edHttpConnectionManager();
2.HttpClient client = new HttpClient(connectionManager);...// 在某个线程
中。
3.GetMethod get = new GetMethod("https://www.sodocs.net/doc/022289453.html,/");
4.try {
5.client.executeMethod(get);// print response to stdout
6.System.out.println(get.getResponseBodyAsStream());
7.} finally {
8.// be sure the connection is released back to the connection
9.managerget.releaseConnection();
10.}
可以看出来,它的方式与jdbc连接池的使用方式相近,我觉得比较不爽的就是需要手动调用releaseConnection去释放连接。对每一个HttpClient.executeMethod须有一个method.releaseConnection()与之匹配。
HttpClient4在这点上做了改进,使用我们常用的InputStream.close()来确认连接关闭(4.1版本之前使用entity.consumeContent()来确认内容已经被消耗关闭连接)。具体方式如下:[java]view plaincopyprint?
1....HttpClient client = null;InputStream in = null;
2.try{
3.client = HttpConnectionManager.getHttpClient();
4.HttpGet get = new HttpGet();
5.get.setURI(new URI(urlPath));
6.HttpResponse response = client.execute(get);
7.HttpEntity entity =response.getEntity();
8.if( entity != null ){
9. in = entity.getContent();
10. ....
11.}catch (Exception e){
12.....
13.}finally{
14.if (in != null){
15.try{in.close ();}catch (IOException e){
16.e.printStackTrace ();
17.}
18.}
19.}
2012-03-06更新:
有网友提出调用in.close()是否会关闭底层socket,事情是这样的:
[plain]view plaincopyprint?
1.回复kangkang203:感谢你提出的这个问题。
2.首先我文中提出的方法in.close()它会触发一个连接的释放这个连接将重新被连接管理
器收回,官网的原文是这么说的:
“Closing the input stream will trigger connection release...the underl
ying connection gets released back to the connection manager”。但是底层
的socket是否会被关闭是不一定的,我看了部分源码(EofSensorInputStream)发现,
大多数情况socket并不会关闭,而是否关闭socket貌似是由一个Watcher去决定的。
所以in.close的调用不会引起socket的关闭。
3.另外,由于http本身我们把它当做“短连接”,所以在一次请求交互完成后仍然打开
socket的意义不是很大,毕竟它不像长连接那样在一个连接建立之后会有很多次数据交
互。我们试用连接管理器的更多意义在于它对连接的管理。
好说完了连接池的使用流程,现在来说一说连接池在使用时最重要的几个参数。我用4.1的版本实现了一个简单的HttpConnectionManager,代码如下:
[java]view plaincopyprint?
1.public class HttpConnectionManager {
2.
3. private static HttpParams httpParams;
4. private static ClientConnectionManager connectionManager;
5.
6. /**
7. * 最大连接数
8. */
9. public final static int MAX_TOTAL_CONNECTIONS = 800;
10. /**
11. * 获取连接的最大等待时间
12. */
13. public final static int WAIT_TIMEOUT = 60000;
14. /**
15. * 每个路由最大连接数
16. */
17. public final static int MAX_ROUTE_CONNECTIONS = 400;
18. /**
19. * 连接超时时间
20. */
21. public final static int CONNECT_TIMEOUT = 10000;
22. /**
23. * 读取超时时间
24. */
25. public final static int READ_TIMEOUT = 10000;
26.
27. static {
28. httpParams = new BasicHttpParams();
29. // 设置最大连接数
30. ConnManagerParams.setMaxTotalConnections(httpParams, MAX_TOTAL
_CONNECTIONS);
31. // 设置获取连接的最大等待时间
32. ConnManagerParams.setTimeout(httpParams, WAIT_TIMEOUT);
33. // 设置每个路由最大连接数
34. ConnPerRouteBean connPerRoute = new ConnPerRouteBean(MAX_ROUTE
_CONNECTIONS);
35. ConnManagerParams.setMaxConnectionsPerRoute(httpParams,connPer
Route);
36. // 设置连接超时时间
37. HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_
TIMEOUT);
38. // 设置读取超时时间
39. HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT);
40.
41. SchemeRegistry registry = new SchemeRegistry();
42. registry.register(new Scheme("http", PlainSocketFactory.getSoc
ketFactory(), 80));
43. registry.register(new Scheme("https", SSLSocketFactory.getSock
etFactory(), 443));
44.
45. connectionManager = new ThreadSafeClientConnManager(httpParams
, registry);
46. }
47.
48. public static HttpClient getHttpClient() {
49. return new DefaultHttpClient(connectionManager, httpParams);
50. }
51.
52.}
最大连接数、获取连接的最大等待时间、读取超时时间这些配置应该比较容易理解,一般的连接池都会有这些配置,比较特别的是每个路由(route)最大连接数。
什么是一个route?
这里route的概念可以理解为运行环境机器到目标机器的一条线路。举例来说,我们使用HttpClient的实现来分别请求https://www.sodocs.net/doc/022289453.html, 的资源和https://www.sodocs.net/doc/022289453.html, 的资源那么他就会产生两个route。
这里为什么要特别提到route最大连接数这个参数呢,因为这个参数的默认值为2,如果不设置这个参数值默认情况下对于同一个目标机器的最大并发连接只有2个!这意味着如果你正在执行一个针对某一台目标机器的抓取任务的时候,哪怕你设置连接池的最大连接数为200,但是实际上还是只有2个连接在工作,其他剩余的198个连接都在等待,都是为别的目标机器服务的。
怎么样蛋疼吧,我是已经有过血的教训了,在切换到HttpClient4.1的起初没有注意到这个配置,最后使得服务承受的压力反而不如从前了,所以在这里特别提醒大家注意。
HttpClient4.X 教程下载:
https://www.sodocs.net/doc/022289453.html,/repos/asf/httpcomponents/httpclient/trunk/httpclient-contrib/docs/tra nslated-tutorial/httpclient-tutorial-simplified-chinese.pdf
关于版本的补充:
网友w2449008821提醒之后我才发现在HttpClient4.1+的版本ConnManagerParams已经被Deprecated了。
我在写这篇日志的时候时候的httpclient版本是4.0.3,从4.0版本之后ConnManagerParams被Deprecated,没想到一个小版本升级会有这么大变化。
官网教程举例了新的连接池设置:
[java]view plaincopyprint?
1.SchemeRegistry schemeRegistry = new SchemeRegistry();
2.schemeRegistry.register(
3. new Scheme("http", 80, PlainSocketFactory.getSocketFactory())
);
4.schemeRegistry.register(
5. new Scheme("https", 443, SSLSocketFactory.getSocketFactory())
);
6.
7.ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(schem
eRegistry);
8.// Increase max total connection to 200
9.cm.setMaxTotalConnections(200);
10.// Increase default max connection per route to 20
11.cm.setDefaultMaxPerRoute(20);
12.// Increase max connections for localhost:80 to 50
13.HttpHost localhost = new HttpHost("locahost", 80);
14.cm.setMaxForRoute(new HttpRoute(localhost), 50);
15.
16.HttpClient httpClient = new DefaultHttpClient(cm);