[英]How does consuming till the end of stream using EntityUtils.consume(httpEntity) result in releasing the connection back to the connection pool?
I read here that EntityUtils.consume(httpEntity)
will result in releasing the connection back to the connection pool, but when I looked at the source code, I couldn't understand how is that happening.我在这里EntityUtils.consume(httpEntity)
将导致将连接释放回连接池,但是当我查看源代码时,我无法理解这是怎么回事。 Can someone please point me to the part of the code where EntityUtils.consume(httpEntity)
or EntityUtils.toString(httpEntity)
is releasing the connection when I'm using Elastic Search Rest Client (org.elasticsearch.client.RestClient - low level rest client) like this: https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-low-usage-responses.html ? Can someone please point me to the part of the code where EntityUtils.consume(httpEntity)
or EntityUtils.toString(httpEntity)
is releasing the connection when I'm using Elastic Search Rest Client (org.elasticsearch.client.RestClient - low level rest客户端)像这样: https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-low-usage-responses.html ?
What happens to the connection if there is a SocketTimeoutException and I don't consume the HttpEntity?如果存在 SocketTimeoutException 并且我不使用 HttpEntity,连接会发生什么情况?
Client-side close and connection release to the Pool (steps)客户端关闭和连接释放到池(步骤)
EntityUtils.consume
& EntityUtils.toString
> the first one will close()
the instream
if it fully consumes the entity. EntityUtils.consume
& EntityUtils.toString
> 如果完全消耗实体,第一个将close()
instream
。 The second one will always call instream.close()
in its finally clause.第二个总是在它的finally子句中调用instream.close()
。 instream
is the name given to the InputStream variable. instream
是 InputStream 变量的名称。
instream
. instream
。 close()
> For this example, the implementation of the InputStream
is a ContentInputStream
. close()
> 对于这个例子, InputStream
的实现是一个ContentInputStream
。 The close()
method forces the ContentInputStream
to be read till its end by the loop mechanism shown in the code snippet. close()
方法通过代码片段中显示的循环机制强制读取ContentInputStream
直到其结束。
Following calls to this stream will lead to an EOF
exception.调用此 stream 将导致EOF
异常。
@Override public void close() throws IOException { final byte tmp[] = new byte[1024]; /*loop until read() is -1, which means, advance the buffer till is end*/ while (this.buffer.read(tmp, 0, tmp.length) >= 0) {} super.close(); }
Pool
> Checks all pooled resources status. Pool
> 检查所有池资源状态。 This operation may be triggered by some actions (as a new request), or may be managed by underlying threads.此操作可能由某些操作(作为新请求)触发,也可能由底层线程管理。 If one resource/stream was closed by the other end, it will get an EOF
exception ( as the buffer was forced to advance to the end ).如果一个资源/流被另一端关闭,它将得到一个EOF
异常(因为缓冲区被迫前进到最后)。 The spot is marked as invalid.该地点被标记为无效。
Pool
> All invalid spots are recycled . Pool
>所有无效点被回收。 It will remove the closed streams and create new ones, or restore the existing ones without the need of erase+create (depending on the resource type).它将删除关闭的流并创建新的流,或者在不需要擦除+创建的情况下恢复现有流(取决于资源类型)。 This means the spot that was holding the stream is avaliable again, with a new stream ready to be used:这意味着持有 stream 的位置再次可用,新的 stream 可以使用:
The connection is released back to the pool.连接被释放回池。 The other end is not using it anymore, so the pool has total control of it.另一端不再使用它,因此池可以完全控制它。 Now the pool is allowed to erase it, restore it, and assign it to another requester.现在允许池删除、恢复它并将其分配给另一个请求者。 . .
Example例子
Let's imagine a Pool
that manages 3 resources, such as HttpConnections
.让我们想象一个管理 3 个资源的Pool
,例如HttpConnections
。 You already have 3 threads using this pool, so the spots are all occupied.你已经有 3 个线程在使用这个池,所以这些点都被占用了。
Meanwhile ThreadZ
waits for a connection to be released back to the Pool同时ThreadZ
等待连接被释放回池
(spot1) [HttpConn1] -- ThreadA
(spot2) [HttpConn2] -- ThreadB
(spot3) [HttpConn3] -- ThreadC
ThreadA
finished its job and closes its connection. ThreadA
完成了它的工作并关闭了它的连接。 The Pool
will notice this when the status of the PoolEntry
is closed .当PoolEntry
的状态为closed时, Pool
会注意到这一点。 Different PoolEntry
implementations will check this is different ways, one of them being getting an EOF
exception while trying to read from a stream.不同PoolEntry
实现会以不同的方式进行检查,其中之一是在尝试从 stream 读取时遇到EOF
异常。 Other implementations could have different mechanisms to check if the resource is closed .其他实现可能有不同的机制来检查资源是否已关闭。 If the PoolEntry
tells that his resource is closed/invalid , the Pool
will recycle this spot.如果PoolEntry
告知他的资源已关闭/无效,则Pool
将回收该点。 There are two options here:这里有两个选项:
a) Erase and create. a) 擦除和创建。
(spot1) [HttpConn4] // the pool removes the old one and creates a new connection
(spot2) [HttpConn2] -- ThreadB
(spot3) [HttpConn3] -- ThreadC
b) Restore. b) 恢复。
(spot1) [HttpConn1] // the pool is able to "reset" the existing resource
(spot2) [HttpConn2] -- ThreadB
(spot3) [HttpConn3] -- ThreadC
"Releasing the connection back" could be translated to "now there's an avaliable spot/resource again". “释放连接”可以翻译为“现在又有一个可用的点/资源”。 The pool can now give a connection to ThreadZ
:池现在可以提供与ThreadZ
的连接:
(spot1) [HttpConn1] -- ThreadZ
(spot2) [HttpConn2] -- ThreadB
(spot3) [HttpConn3] -- ThreadC
consume
/ toString
- connection release consume
/ toString
- 连接释放
All explained above means that calling close()
in the InputStream
will trigger the connection release .上面所有的解释意味着在InputStream
中调用close()
将触发连接释放。
This happens both in consume
( if the entity content is fully consumed ) and toString
methods:这发生在consume
(如果实体内容被完全消费)和toString
方法中:
public static void consume(final HttpEntity entity) throws IOException
{
if (entity == null)
return;
if (entity.isStreaming())
{
InputStream instream = entity.getContent();
if (instream != null)
instream.close(); // <-- connection release
}
}
public static String toString(final HttpEntity entity, final Charset defaultCharset)
throws IOException, ParseException
{
Args.notNull(entity, "Entity");
InputStream instream = entity.getContent();
if (instream == null) {
return null;
}
try {
Args.check(entity.getContentLength() <= Integer.MAX_VALUE,
"HTTP entity too large to be buffered in memory");
int i = (int)entity.getContentLength();
if (i < 0) {
i = 4096;
}
Charset charset = null;
try {
ContentType contentType = ContentType.getOrDefault(entity);
charset = contentType.getCharset();
} catch (UnsupportedCharsetException ex) {
throw new UnsupportedEncodingException(ex.getMessage());
}
if (charset == null) {
charset = defaultCharset;
}
if (charset == null) {
charset = HTTP.DEF_CONTENT_CHARSET;
}
Reader reader = new InputStreamReader(instream, charset);
CharArrayBuffer buffer = new CharArrayBuffer(i);
char[] tmp = new char[1024];
int l;
while((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
return buffer.toString();
} finally {
instream.close(); // <--- connection release
}
}
What happens to the connection if there is a SocketTimeoutException and I don't consume the HttpEntity?如果存在 SocketTimeoutException 并且我不使用 HttpEntity,连接会发生什么情况?
As you notice, both methods throw an IOException
, and SocketTimeoutException
is inherited from it.正如您所注意到的,这两种方法都抛出一个IOException
,并且SocketTimeoutException
是从它继承而来的。 It is responsability of the caller to catch this exception and manage to close all resources if such scenario happens.如果发生这种情况,调用者有责任捕获此异常并设法关闭所有资源。 For example:例如:
void tryConsume()
{
try
{
//...
EntityUtils.consume(httpEntity);
//...
}
catch (IOException)
{
//SocketTimeoutException happened. Log the error,etc
// (Close resources here...)
}
finally
{
//...Or maybe include a finally clause and close them here, if you wish
// them to be closed regardless of success/failure.
if (httpEntity!=null)
{
InputStream instream = httpEntity.getContent();
if (instream != null)
instream.close(); /* <-- connection release. when checking this
spot, the pool will get (f.e) an EOF
exception. This will lead to replacing this
resource with a fresh new connection and
setting the spot status as avaliable. */
}
}
}
Notice that if a SocketTimeoutException
is thrown, specific PoolEntry
implementations could also check if the resource is invalid without the need of a close()
call.请注意,如果抛出SocketTimeoutException
,特定PoolEntry
实现还可以检查资源是否无效,而无需调用close()
。 Using close()
guarantees that the Pool
will recycle the spot after a correct use of it, and can be used as well as a "invalid marker" when you are able to catch a thrown exception.使用close()
可以保证Pool
在正确使用后回收该点,并且当您能够捕获抛出的异常时,可以将其用作“无效标记”。
But specific Pool
implementations will be able to also check if a resource is invalid even if an uncatched Exception
didn't let you specifically call close()
, as they would be able to check the status with different mechanisms.但是即使未捕获的Exception
不允许您专门调用close()
,特定的Pool
实现也将能够检查资源是否无效,因为它们将能够使用不同的机制检查状态。 For example, checking how many time a connection was in IDLE
state .例如,检查连接在IDLE
state 中的时间。 If this time is superior to a certain treshold marked by the Pool
, this spot will be recycled without the need of a previous close()
call from the client.如果此时间优于Pool
标记的某个阈值,则该点将被回收,而无需客户端先前的close()
调用。
This time the Pool
will be the end that calls close()
on it, avoiding a possible deadlock
in the client side, if this one doesn't manage the max connection time or certain exceptions.这一次Pool
将是调用close()
的结束,如果这个不管理最大连接时间或某些异常,则避免客户端可能出现deadlock
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.