欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Apache HttpClient的3是个超时时间的具体含义及HttpClient是否可重用

程序员文章站 2022-05-21 20:37:41
...

最近在写一个调URL程序时,使用了HttpClient,但是我的调用是多个线程的,因此我就在想,HttpClient是每次都需要创建,还是可以重用,带着这个问题,就去官网上溜了一圈,果然没有失望。仅此作为笔记,以备后用。

1.HttpClient是否可重用

文档为Http client 4.5的:章节为:1.2.1-1.2.2

http://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/fundamentals.html#d5e217

1.2.1. HttpClient thread safety

HttpClient implementations are expected to be thread safe. It is recommended that the same instance of this class is reused for multiple request executions.

 

1.2.2. HttpClient resource deallocation

When an instance CloseableHttpClient is no longer needed and is about to go out of scope the connection manager associated with it must be shut down by calling the CloseableHttpClient#close() method.

CloseableHttpClient httpclient = HttpClients.createDefault();

try {

    <...>

} finally {

    httpclient.close();

}

GOOGLE翻译:

1.2.1。HttpClient线程安全

HttpClient实现预计是线程安全的。建议将此类的同一实例重用于多个请求执行。

 

1.2.2。HttpClient资源释放

当CloseableHttpClient不再需要实例并且即将超出范围时,必须通过调用该CloseableHttpClient#close() 方法来关闭与其关联的连接管理器。

2.HttpClient用完后需要释放资源

如上所说,要求释放资源。好像我在1.3版本的文档中看到,如果不自己释放,它会一直等待直到断开连接?

3.多线程调用 

在2.4节中介绍了多线程请求,和我当前的使用场景是一致的。

http://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/connmgmt.html#d5e405

2.4. Multithreaded request execution

When equipped with a pooling connection manager such as PoolingClientConnectionManager, HttpClient can be used to execute multiple requests simultaneously using multiple threads of execution.

 

The PoolingClientConnectionManager will allocate connections based on its configuration. If all connections for a given route have already been leased, a request for a connection will block until a connection is released back to the pool. One can ensure the connection manager does not block indefinitely in the connection request operation by setting 'http.conn-manager.timeout' to a positive value. If the connection request cannot be serviced within the given time period ConnectionPoolTimeoutException will be thrown.

 

当配备池连接管理器(如 PoolingClientConnectionManagerHttpClient)时,可以使用HttpClient同时使用多个执行线程执行多个请求。

PoolingClientConnectionManager将分配根据其配置的连接。如果已经租用了给定路由的所有连接,则会阻止连接请求,直到将连接释放回池中。通过设置'http.conn-manager.timeout' 为正值,可以确保连接管理器不会无限期地阻塞连接请求操作如果在给定时间段内无法提供服务的连接请求ConnectionPoolTimeoutException将被抛出。

 

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
CloseableHttpClient httpClient = HttpClients.custom()
        .setConnectionManager(cm)
        .build();

// URIs to perform GETs on
String[] urisToGet = {
    "http://www.domain1.com/",
    "http://www.domain2.com/",
    "http://www.domain3.com/",
    "http://www.domain4.com/"
};

// create a thread for each URI
GetThread[] threads = new GetThread[urisToGet.length];
for (int i = 0; i < threads.length; i++) {
    HttpGet httpget = new HttpGet(urisToGet[i]);
    threads[i] = new GetThread(httpClient, httpget);
}

// start the threads
for (int j = 0; j < threads.length; j++) {
    threads[j].start();
}

// join the threads
for (int j = 0; j < threads.length; j++) {
    threads[j].join();
}

While HttpClient instances are thread safe and can be shared between multiple threads of execution, it is highly recommended that each thread maintains its own dedicated instance of HttpContext .

虽然HttpClient实例是线程安全的,并且可以在多个执行线程之间共享,但强烈建议每个线程维护自己的专用实例HttpContext 

static class GetThread extends Thread {

    private final CloseableHttpClient httpClient;
    private final HttpContext context;
    private final HttpGet httpget;

    public GetThread(CloseableHttpClient httpClient, HttpGet httpget) {
        this.httpClient = httpClient;
        this.context = HttpClientContext.create();
        this.httpget = httpget;
    }

    @Override
    public void run() {
        try {
            CloseableHttpResponse response = httpClient.execute(
                    httpget, context);
            try {
                HttpEntity entity = response.getEntity();
            } finally {
                response.close();
            }
        } catch (ClientProtocolException ex) {
            // Handle protocol errors
        } catch (IOException ex) {
            // Handle I/O errors
        }
    }

}

4.总结

 从官网给的例子代码中,可以看到多线程调用中,使用了一个HttpClient,这说明HttpClient支持并发调用。

1.从文档上来看是用来PoolingClientConnectionManager连接管理器时,才会并发请求,是不是真的这样?

2.但是有一个要求,就是强烈建议,每个线程使用自己的HttpContext:HttpClientContext.create(); 

5.连接官理器

在多线程中使用了连接管理器:PoolingClientConnectionManager

2.3.3. Pooling connection manager

PoolingHttpClientConnectionManager is a more complex implementation that manages a pool of client connections and is able to service connection requests from multiple execution threads. Connections are pooled on a per route basis. A request for a route for which the manager already has a persistent connection available in the pool will be serviced by leasing a connection from the pool rather than creating a brand new connection.

 

PoolingHttpClientConnectionManager maintains a maximum limit of connections on a per route basis and in total. Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total. For many real-world applications these limits may prove too constraining, especially if they use HTTP as a transport protocol for their services.

 

This example shows how the connection pool parameters can be adjusted:

PoolingHttpClientConnectionManager是一个更复杂的实现,它管理客户端连接池,并且能够为来自多个执行线程的连接请求提供服务。连接以每个路由为基础进行池化。管理员已经在池中提供持久连接的路由请求将通过从池租用连接而不是创建全新连接来进行服务。

PoolingHttpClientConnectionManager保持每个路由和总计的最大连接数限制。默认情况下,此实现将为每个给定路由创建不超过2个并发连接,并且总共不再有20个连接。对于许多实际应用程序而言,这些限制可能过于严格,尤其是当它们使用HTTP作为其服务的传输协议时。

此示例显示如何调整连接池参数:

 

 

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Increase max connections for localhost:80 to 50
HttpHost localhost = new HttpHost("locahost", 80);
cm.setMaxPerRoute(new HttpRoute(localhost), 50);

CloseableHttpClient httpClient = HttpClients.custom()
        .setConnectionManager(cm)
        .build();

6.连接管理器需要释放

 

 2.3.4. Connection manager shutdown

When an HttpClient instance is no longer needed and is about to go out of scope it is important to shut down its connection manager to ensure that all connections kept alive by the manager get closed and system resources allocated by those connections are released.

当不再需要HttpClient实例并且即将超出范围时,关闭其连接管理器以确保管理器保持活动的所有连接都被关闭并释放这些连接分配的系统资源是很重要的。

 

CloseableHttpClient httpClient = <...>
httpClient.close();

从代码示例看可以看出,释放连接管理器就是释放HttpClient。果真这样?好像和常见的不太一样。

创建了一个PoolingHttpClientConnectionManager,发现这个类的实例有个close方法,这个方法是把其中的实体全部关闭了。难道这是官网文档的错误?

 

7.超时时间

之前也设置过这个时间,上次找了一遍,现在又全忘了,所以这里记录一下,以备后用。

三个超时时间详解:

1.从连接池中获取可用连接超时

HttpClient中的要用连接时尝试从连接池中获取,若是在等待了一定的时间后还没有获取到可用连接(比如连接池中没有空闲连接了)

则会抛出获取连接超时异常。

 

2.连接目标超时connectionTimeout

 指的是连接目标url的连接超时时间,即客服端发送请求到与目标url建立起连接的最大时间。如果在该时间范围内还没有建立起连接,则就

抛出connectionTimeOut异常。如测试的时候,将url改为一个不存在的url:“http://test.com” ,超时时间3000ms过后,系统报出异常:   

org.apache.commons.httpclient.ConnectTimeoutException:The host did not accept the connection within timeout of 3000 ms 

 

3.等待响应超时(读取数据超时)socketTimeout 

   连接上一个url后,获取response的返回等待时间 ,即在与目标url建立连接后,等待放回response的最大时间,在规定时间内没有返回响应的话就抛出SocketTimeout。

   测试的时候的连接url为我本地开启的一个url,http://localhost:8080/firstTest.htm?method=test,在我这个测试url里,当访问到这个链接时,线程sleep一段时间,来模拟返回response超时。 

 

CloseableHttpClient httpclient = HttpClients.createDefault();  
HttpGet httpGet = new HttpGet("http://*.com/");  
RequestConfig requestConfig = RequestConfig.custom()  
        .setConnectTimeout(5000).setConnectionRequestTimeout(1000)  
        .setSocketTimeout(5000).build();  
httpGet.setConfig(requestConfig);  
CloseableHttpResponse response = httpclient.execute(httpGet);  
System.out.println("得到的结果:" + response.getStatusLine());//得到请求结果  
HttpEntity entity = response.getEntity();//得到请求回来的数据

 参考: 

HttpClient超时设置详解,写的非常详细,还有各版本比较。

HttpClient 4.5.2版本设置连接超时时间-CloseableHttpClient设置Timeout

 

完结。