我不清楚是否必须关闭JAX RS客户端/响应实例。如果我必须,永远或不是吗?
根据documentation关于客户端类:
有效地调用此方法会使所有资源目标无效 由客户端实例生成。
WebTarget类没有任何invalidate()/ close()方法,但Response类却有。 根据{{3}}:
关闭基础消息实体输入流(如果可用和 open)以及释放与之相关的任何其他资源 响应(例如缓冲的消息实体数据)。
... close()方法 应该在包含未消耗实体的所有实例上调用 输入流以确保与实例关联的资源 正确清理并防止潜在的内存泄漏。这是 典型的应用程序层代码的客户端方案 仅处理响应头并忽略响应实体。
最后一段对我来说并不清楚。 “未消耗的实体输入流”是什么意思?如果我从响应中获取InputSteam或String,是否应该明确关闭响应?
我们可以在无法访问Response实例的情况下获得响应结果:
Client client = ...;
WebTarget webTarget = ...;
Invocation.Builder builder = webTarget.request(MediaType.APPLICATION_JSON_TYPE);
Invocation invocation = builder.buildGet();
InputStream reso = invocation.invoke(InputStream.class);
我正在使用RESTeasy实现,我期望在resteasy实现中关闭响应,但我找不到它。谁能告诉我为什么? 我知道documentation 但即使知道,也会使用响应,而不关闭它。
答案 0 :(得分:3)
根据文件close()
是幂等的。
此操作是幂等的,即它可以多次调用并具有相同的效果,这也意味着在已经关闭的消息实例上调用close()方法是合法的并且没有进一步的效果。
所以你可以安全地关闭InputStream
并且应该。
据说我风格明智不会invocation.invoke(InputStream.class)
,因为invoker(Class)
是为了进行实体转换而做的。相反,如果你想要InputStream,你可能只需要调用invocation.invoke()
并直接处理Response
对象,因为在阅读流之前你可能需要一些头信息。
在处理响应时需要标题的原因InputStream
是典型的,因为您不关心正文或正文需要特殊处理和大小考虑因素,这是文档提到的内容(例如{{1}请求ping服务器)。
另见link
将缓存从此方法返回的消息实例,以便通过getEntity()进行后续检索。除非提供的实体类型是输入流,否则此方法会在打开时自动关闭未使用的原始响应实体数据流。如果实体数据已被缓冲,则在使用缓冲数据之前将重置缓冲区,以便在此响应上启用readEntity(...)方法的后续调用。
因此,如果您选择HEAD
以外的任何其他内容,则无需关闭InputStream
(但无论如何都可以安全地将其作为幂等元素)。
答案 1 :(得分:1)
简而言之:请调用close()或在try-with-resources-statement中使用closeable。
资源/参考:
根据Resteasy documentation,应在Response引用上调用close()。 最后在第47.3节中指出
Resteasy将释放底盖下的连接。唯一的 反例是响应是以下实例的情况 InputStream,必须明确关闭。
另一方面,如果调用的结果是的一个实例 Response,然后使用Response。 close ()方法来释放 连接。
您可能应该在try / finally块中执行此操作。再次, 释放连接只会使其可供其他使用。它 通常不会关闭套接字。
请注意,如果ApacheHttpClient4Engine创建了自己的实例, HttpClient,不必等待finalize() close 打开 插座。 ClientHttpEngine接口为此具有 close ()方法 目的。
最后,如果您的javax.ws.rs.client.Client类创建了 为您自动创建引擎,您应该致电Client。关闭()和 这将清除所有套接字连接。
答案 2 :(得分:0)
查看resteasy-client
源代码,Invocation#invoke(Class<T>)
只需调用Invocation#invoke()
并调用Invocation#extractResult(GenericType<T> responseType, Response response, Annotation[] annotations)
即可从Response
中提取结果:
@Override
public <T> T invoke(Class<T> responseType)
{
Response response = invoke();
if (Response.class.equals(responseType)) return (T)response;
return extractResult(new GenericType<T>(responseType), response, null);
}
Invocation#extractResult(GenericType<T> responseType, Response response, Annotation[] annotations)
关闭finally
块中的响应:
/**
* Extracts result from response throwing an appropriate exception if not a successful response.
*
* @param responseType
* @param response
* @param annotations
* @param <T>
* @return
*/
public static <T> T extractResult(GenericType<T> responseType, Response response, Annotation[] annotations)
{
int status = response.getStatus();
if (status >= 200 && status < 300)
{
try
{
if (response.getMediaType() == null)
{
return null;
}
else
{
T rtn = response.readEntity(responseType, annotations);
if (InputStream.class.isInstance(rtn)
|| Reader.class.isInstance(rtn))
{
if (response instanceof ClientResponse)
{
ClientResponse clientResponse = (ClientResponse)response;
clientResponse.noReleaseConnection();
}
}
return rtn;
}
}
catch (WebApplicationException wae)
{
try
{
response.close();
}
catch (Exception e)
{
}
throw wae;
}
catch (Throwable throwable)
{
try
{
response.close();
}
catch (Exception e)
{
}
throw new ResponseProcessingException(response, throwable);
}
finally
{
if (response.getMediaType() == null) response.close();
}
}
try
{
// Buffer the entity for any exception thrown as the response may have any entity the user wants
// We don't want to leave the connection open though.
String s = String.class.cast(response.getHeaders().getFirst("resteasy.buffer.exception.entity"));
if (s == null || Boolean.parseBoolean(s))
{
response.bufferEntity();
}
else
{
// close connection
if (response instanceof ClientResponse)
{
try
{
ClientResponse.class.cast(response).releaseConnection();
}
catch (IOException e)
{
// Ignore
}
}
}
if (status >= 300 && status < 400) throw new RedirectionException(response);
return handleErrorStatus(response);
}
finally
{
// close if no content
if (response.getMediaType() == null) response.close();
}
}