在我们的一个项目中,我们需要使用httpClient
从后端服务中获取一些数据。我们发现遗留代码没有正确关闭响应。
代码如下:
HttpResponse response = httpClient.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
return EntityUtils.toString(response.getEntity());
} else {
throw new InvalidResponseException();
}
当statusCode
为200
时,EntityUtils.toString
将使用响应的内容,然后正确关闭它。但在其他情况下,响应没有关闭,我们将有http连接泄漏(一段时间后,httpClient池运行,我们无法获得新线程)
代码库上有很多这样的代码,所以我想使用加载设计模式来简化它。
我定义了一个HttpClientWrapper
,如:
class HttpClientWrapper {
private HttpClient client;
public HttpClientWrapper(HttpClient client) {
this.client = client;
}
public <T> T execute(HttpRequestBase request, WithResponse<T> handler) {
HttpResponse response = null;
try {
response = client.execute(request);
return handler.withResponse(response);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (response != null) {
EntityUtils.consumeQuietly(response.getEntity());
}
}
}
}
interface WithResponse<T> {
T withResponse(HttpResponse response) throws Exception;
}
我在finally
的包装器中消耗了响应,因此响应将始终正确关闭。我可以愉快地使用它更改现有代码:
return new HttpClientWrapper(httpClient).execute(request, new WithResponse<String>() {
String withResponse(HttpResponse response) throws Exception {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
return EntityUtils.toString(response.getEntity());
} else {
throw new InvalidResponseException();
}
}
});
我不再需要担心泄漏。
但突然间我发现了这么一段代码:
Stopwatch stopwatch = new Stopwatch();
try {
stopwatch.start();
HttpResponse response = httpClient.execute( request );
stopwatch.stop();
MDC.put( "backendTime", String.valueOf( stopwatch.elapsed( TimeUnit.MILLISECONDS ) ) );
return EntityUtils.toString(response.getEntity());
} catch( IOException e ) {
throw new RuntimeException( e );
}
需要检查httpClient用于获取响应的时间长度!我不能在这里使用HttpClientWrapper
,因为我无法找到一种方法来衡量每个当前设计的整个过程的一部分。
我现在有两个选择:
不要将HttpClientWrapper
用于此代码,我们需要手动关闭响应。 (但获得回应的方式不再一致)
修改HttpClientWrapper
,使其变得复杂并且足够灵活以满足此要求。 (但只有一个地方需要它)
我不喜欢,还有其他更好的解决方案吗?
答案 0 :(得分:2)
是什么阻止您在包装器之前初始化StopWatch
并在回调中停止它?
final Stopwatch stopwatch = new Stopwatch();
stopwatch.start();
new HttpClientWrapper(httpClient).execute(request, new WithResponse<String>() {
String withResponse(HttpResponse response) throws Exception {
stopwatch.stop();
MDC.put( "backendTime", String.valueOf( stopwatch.elapsed( TimeUnit.MILLISECONDS ) ) );
// ...
}
});