Closing connection in GET request using Jersey Cli

2019-02-05 03:03发布

问题:

I am using Jersey client for REST calls from Java code:

<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.22.1</version>
</dependency> 

In my GET request,

javax.ws.rs.client.Invocation.Builder builder = ClientBuilder.newClient().target(url).request(); 
builder.get().readEntity(String.class);

the client will be closed automatically after calling readEntity(String.class).

If I use,

builder.get(String.class);  

I get the same output.

Is the connection closed automatically or do I need to close it manually in this case?

回答1:

Short answer

Consider the following code:

Client client = ClientBuilder.newClient();
String result = client.target(url).request().get(String.class);

Under the hood, Jersey invokes Response#readEntity(Class<T>) if the request has succeeded and the connection will be closed for you. So the connection doesn't need to be closed manually in this situation.

Now consider the following code:

Client client = ClientBuilder.newClient();
Response response = client.target(url).request().get();

For this situation, you need to invoke Response#close() to close the connection. Or invoke Response#readEntity(Class<T>) to make Jersey close the connection for you.

Long answer

As stated in the documentation, if you don't read the entity, then you need to close the response manually by invoking Response#close().

For more details, have a look at Jersey's documentation about how to close connections:

5.7. Closing connections

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.

Additionally, have a look at JerseyInvocation source. The most important parts are quoted below.

In the translate(ClientResponse, RequestScope, Class<T>) method you'll see that response.readEntity(Class<T>) is invoked.

JerseyInvocation.Builder#get(Class<T>)

Invoke HTTP GET method for the current request synchronously.

@Override
public <T> T get(final Class<T> responseType)
    throws ProcessingException, WebApplicationException {

    return method("GET", responseType);
}

JerseyInvocation.Builder#method(String, Class<T>)

Invoke an arbitrary method for the current request synchronously.

@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>)

Synchronously invoke the request and receive a response of the specified type back.

@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>)

If the request suceeded, the response entity is read as an instance of specified Java type using 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));
    }
}