使用jersey的JAX RS的内存问题

Tho*_*mas 2 java rest performance jersey java-memory-leaks

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

  1. 如何正确共享JAX-RS 2.0客户端
  2. 关闭JAX RS客户端/响应
  3. 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

cas*_*lin 10

Client 实例应该重用

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

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

WebTarget 实例可以重用

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

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

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

改善您的代码

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

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

@Singleton
public class MyBean {

    private Client client;

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

    ...

    @PreDestroy
    public void onDestroy() {
        this.client.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

使用连接池

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

正如我在旧答案中所提到的,默认情况下,Jersey中的传输层由提供HttpURLConnection.这种支持在泽西岛实施HttpUrlConnectorProvider.如果需要,可以替换默认连接器,并使用连接池以获得更好的性能.

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

<dependency>
    <groupId>org.glassfish.jersey.connectors</groupId>
    <artifactId>jersey-apache-connector</artifactId>
    <version>2.26</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

然后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);
Run Code Online (Sandbox Code Playgroud)

有关其他详细信息,请参阅有关连接器的Jersey文档.