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