使用jersey的JAX RS的内存问题

我们目前在高效的服务器上遇到了一些麻烦,因为它消耗的内存过多.其中一个漏洞可能来自球衣客户端.我发现了以下两个问题以及如何:

> How to correctly share JAX-RS 2.0 client
> Closing JAX RS Client/Response
> https://blogs.oracle.com/japod/entry/how_to_use_jersey_client

我从中获得了什么,我应该重用客户端,还可能重用WebTargets?
同时建议关闭响应,但是如何使用.request()执行此操作?

代码示例,使用不同的路径每小时调用大约1000次:

public byte[] getDocument(String path) {
    Client client = ClientBuilder.newClient();
    WebTarget target = client.target(config.getPublishHost() + path);
    try {
        byte[] bytes = target.request().get(byte[].class);
        LOGGER.debug("Document size in bytes: " + bytes.length);
        return bytes;
    } catch (ProcessingException e) {
        LOGGER.error(Constants.PROCESSING_ERROR, e);
        throw new FailureException(Constants.PROCESSING_ERROR, e);
    } catch (WebApplicationException e) {
        LOGGER.error(Constants.RESPONSE_ERROR, e);
        throw new FailureException(Constants.RESPONSE_ERROR, e);
    } finally {
        client.close();
    }
}

所以我的问题是如何正确使用API​​来防止上述示例的泄漏?

解决方法:

应重用客户端实例

Client个实例是重量级对象,用于管理底层客户端通信基础架构.因此,初始化以及处理Client实例可能是相当昂贵的操作.

documentation建议只创建少量的Client个实例,并在可能的情况下重用它们.它还指出,在处置之前必须正确关闭Client个实例以避免资源泄漏.

WebTarget实例可以重用

如果对同一路径执行多个请求,则可以重用WebTarget个实例.如果它们有一些configuration,建议重新使用WebTarget实例.

如果您不读取实体,则应关闭响应实例

应关闭包含未消耗实体输入流的Response个实例.这通常仅适用于仅处理响应标头和状态代码的情况,忽略响应实体.有关关闭Response实例的更多详细信息,请参见answer.

改善您的代码

对于您的问题中提到的情况,您希望确保将Client实例重用于所有getDocument(String)方法调用.

例如,如果您的应用程序是基于CDI的,则在构造bean时创建一个Client实例,并在销毁之前将其处置.在下面的示例中,Client实例存储在单例bean中:

@Singleton
public class MyBean {

    private Client client;

    @PostConstruct
    public void onCreate() {
        this.client = ClientBuilder.newClient();
    }

    ...

    @PreDestroy
    public void onDestroy() {
        this.client.close();
    }
}

您不需要(或者可能不能)重用WebTarget实例(每个方法调用请求的路径更改).当您将实体读入byte []时,Response实例将自动关闭.

使用连接池

连接池可以很好地提高性能.

正如我早期的answer中所提到的,默认情况下,Jersey中的传输层由HttpURLConnection提供.此支持在Jersey通过HttpUrlConnectorProvider实现.如果需要,可以替换默认连接器并使用连接池以获得更好的性能.

Jersey通过ApacheConnectorProvider与Apache HTTP Client集成.要使用它,请添加以下依赖项:

<dependency>
    <groupId>org.glassfish.jersey.connectors</groupId>
    <artifactId>jersey-apache-connector</artifactId>
    <version>2.26</version>
</dependency>

然后按如下方式创建您的Client实例:

PoolingHttpClientConnectionManager connectionManager = 
        new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(5);

ClientConfig clientConfig = new ClientConfig();
clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
clientConfig.connectorProvider(new ApacheConnectorProvider());

Client client = ClientBuilder.newClient(clientConfig);

有关其他详细信息,请参阅Jersey documentation about connectors.

上一篇:java – 如何在Jersey中使用自定义验证


下一篇:java – 使用Jersey进行多线程处理