使用 Jersey Client 2.22.1 在 GET 请求中关闭连接
Closing connection in GET request using Jersey Client 2.22.1
我正在使用 Jersey 客户端从 Java 代码进行 REST 调用:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.22.1</version>
</dependency>
在我的 GET 请求中,
javax.ws.rs.client.Invocation.Builder builder = ClientBuilder.newClient().target(url).request();
builder.get().readEntity(String.class);
调用readEntity(String.class)
后客户端会自动关闭。
如果我用,
builder.get(String.class);
我得到了相同的输出。
在这种情况下,连接是自动关闭还是我需要手动关闭?
简答
考虑以下代码:
Client client = ClientBuilder.newClient();
String result = client.target(url).request().get(String.class);
在后台,如果请求成功,Jersey 会调用 Response#readEntity(Class<T>)
并且将为您关闭连接。 所以这种情况不需要手动关闭连接。
现在考虑以下代码:
Client client = ClientBuilder.newClient();
Response response = client.target(url).request().get();
对于这种情况,您需要调用Response#close()
来关闭连接。或者调用 Response#readEntity(Class<T>)
让 Jersey 为您关闭连接。
长答案
如documentation, if you don't read the entity, then you need to close the response manually by invoking Response#close()
中所述。
有关更多详细信息,请查看关于如何关闭连接的 Jersey documentation:
The underlying connections are opened for each request and closed
after the response is received and entity is processed (entity is
read). See the following example:
final WebTarget target = ... some web target
Response response = target.path("resource").request().get();
System.out.println("Connection is still open.");
System.out.println("string response: " + response.readEntity(String.class));
System.out.println("Now the connection is closed.");
If you don't read the entity, then you need to close the response
manually by response.close()
.
Also if the entity is read into an
InputStream
(by response.readEntity(InputStream.class)
), the
connection stays open until you finish reading from the InputStream
.
In that case, the InputStream
or the Response
should be closed
manually at the end of reading from InputStream
.
另外,看看JerseyInvocation
source。下面引用了最重要的部分。
在 translate(ClientResponse, RequestScope, Class<T>)
方法中,您会看到 response.readEntity(Class<T>)
被调用。
JerseyInvocation.Builder#get(Class<T>)
为当前请求同步调用 HTTP GET
方法。
@Override
public <T> T get(final Class<T> responseType)
throws ProcessingException, WebApplicationException {
return method("GET", responseType);
}
JerseyInvocation.Builder#method(String, Class<T>)
同步调用当前请求的任意方法。
@Override
public <T> T method(final String name, final Class<T> responseType)
throws ProcessingException, WebApplicationException {
// responseType null check omitted for brevity
requestContext.setMethod(name);
return new JerseyInvocation(this).invoke(responseType);
}
JerseyInvocation#invoke(Class<T>)
同步调用请求并接收指定类型的响应。
@Override
public <T> T invoke(final Class<T> responseType)
throws ProcessingException, WebApplicationException {
// responseType null check omitted for brevity
final ClientRuntime runtime = request().getClientRuntime();
final RequestScope requestScope = runtime.getRequestScope();
return requestScope.runInScope(new Producer<T>() {
@Override
public T call() throws ProcessingException {
try {
return translate(runtime.invoke(requestForCall(requestContext)),
requestScope, responseType);
} catch (final ProcessingException ex) {
// Exception handling omitted for brevity
}
}
});
}
JerseyInvocation#translate(ClientResponse, RequestScope, Class<T>)
如果请求成功,则使用 Response#readEntity(Class<T>)
:
将响应实体读取为指定 Java 类型的实例
private <T> T translate(final ClientResponse response, final RequestScope scope,
final Class<T> responseType) throws ProcessingException {
if (responseType == Response.class) {
return responseType.cast(new InboundJaxrsResponse(response, scope));
}
if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) {
try {
return response.readEntity(responseType);
} catch (final ProcessingException ex) {
// Exception handling omitted for brevity
}
} else {
throw convertToException(new InboundJaxrsResponse(response, scope));
}
}
我正在使用 Jersey 客户端从 Java 代码进行 REST 调用:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.22.1</version>
</dependency>
在我的 GET 请求中,
javax.ws.rs.client.Invocation.Builder builder = ClientBuilder.newClient().target(url).request();
builder.get().readEntity(String.class);
调用readEntity(String.class)
后客户端会自动关闭。
如果我用,
builder.get(String.class);
我得到了相同的输出。
在这种情况下,连接是自动关闭还是我需要手动关闭?
简答
考虑以下代码:
Client client = ClientBuilder.newClient();
String result = client.target(url).request().get(String.class);
在后台,如果请求成功,Jersey 会调用 Response#readEntity(Class<T>)
并且将为您关闭连接。 所以这种情况不需要手动关闭连接。
现在考虑以下代码:
Client client = ClientBuilder.newClient();
Response response = client.target(url).request().get();
对于这种情况,您需要调用Response#close()
来关闭连接。或者调用 Response#readEntity(Class<T>)
让 Jersey 为您关闭连接。
长答案
如documentation, if you don't read the entity, then you need to close the response manually by invoking Response#close()
中所述。
有关更多详细信息,请查看关于如何关闭连接的 Jersey documentation:
The underlying connections are opened for each request and closed after the response is received and entity is processed (entity is read). See the following example:
final WebTarget target = ... some web target Response response = target.path("resource").request().get(); System.out.println("Connection is still open."); System.out.println("string response: " + response.readEntity(String.class)); System.out.println("Now the connection is closed.");
If you don't read the entity, then you need to close the response manually by
response.close()
.Also if the entity is read into an
InputStream
(byresponse.readEntity(InputStream.class)
), the connection stays open until you finish reading from theInputStream
. In that case, theInputStream
or theResponse
should be closed manually at the end of reading fromInputStream
.
另外,看看JerseyInvocation
source。下面引用了最重要的部分。
在 translate(ClientResponse, RequestScope, Class<T>)
方法中,您会看到 response.readEntity(Class<T>)
被调用。
JerseyInvocation.Builder#get(Class<T>)
为当前请求同步调用 HTTP GET
方法。
@Override
public <T> T get(final Class<T> responseType)
throws ProcessingException, WebApplicationException {
return method("GET", responseType);
}
JerseyInvocation.Builder#method(String, Class<T>)
同步调用当前请求的任意方法。
@Override
public <T> T method(final String name, final Class<T> responseType)
throws ProcessingException, WebApplicationException {
// responseType null check omitted for brevity
requestContext.setMethod(name);
return new JerseyInvocation(this).invoke(responseType);
}
JerseyInvocation#invoke(Class<T>)
同步调用请求并接收指定类型的响应。
@Override
public <T> T invoke(final Class<T> responseType)
throws ProcessingException, WebApplicationException {
// responseType null check omitted for brevity
final ClientRuntime runtime = request().getClientRuntime();
final RequestScope requestScope = runtime.getRequestScope();
return requestScope.runInScope(new Producer<T>() {
@Override
public T call() throws ProcessingException {
try {
return translate(runtime.invoke(requestForCall(requestContext)),
requestScope, responseType);
} catch (final ProcessingException ex) {
// Exception handling omitted for brevity
}
}
});
}
JerseyInvocation#translate(ClientResponse, RequestScope, Class<T>)
如果请求成功,则使用 Response#readEntity(Class<T>)
:
private <T> T translate(final ClientResponse response, final RequestScope scope,
final Class<T> responseType) throws ProcessingException {
if (responseType == Response.class) {
return responseType.cast(new InboundJaxrsResponse(response, scope));
}
if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) {
try {
return response.readEntity(responseType);
} catch (final ProcessingException ex) {
// Exception handling omitted for brevity
}
} else {
throw convertToException(new InboundJaxrsResponse(response, scope));
}
}