我的设置:我创建了一个REST服务(Jersey / Dropwizard),该服务从数据库中流式传输大量内容。在GET操作期间,该服务通过连接池进入数据库,将数据包装到流中,并进行一些即时转换,以各种编码(CSV,JSON,...)呈现请求的数据。数据库连接的生命周期与流的生命周期息息相关,只有当流关闭时,数据库连接才会被释放。
流转换由Encoder类执行,该类返回StreamingOutput,然后将其传递到Response对象。当流被完全消耗时,编码器当前处理资源关闭。
我的问题:由于 StreamingOutput 没有实现 AutoCloseable ,因此当仅部分消耗输出时可能会发生连接泄漏。
我有时会发现连接池中堆积了陈旧的活动连接,并且我怀疑它们是由HTTP连接中断引起的。如下所示,当前代码处理 try 块中发生的异常。我无法处理的是在return语句之后发生的异常,而且我不知道如何将任何用于关闭资源的指令附加到 Response 对象。
我的问题:在请求终止(正常或由于错误)之后,如何通知 Response 对象关闭特定资源?或者:当请求上下文结束时,有没有更好的方法安全地关闭任何关联的资源?
@GET
//@Produces(...)
public Response streamData(
@PathParam("key") String key,
// ... other params
) {
//decode and validate params
Stream<Pojo> ps = null;
try {
// connect to db and obtain data stream for <key>
ps = loadData(db, key);
// apply detailed encoding instrunctions and create a StreamingOutput
final StreamingOutput stream = Encoder.encodeData(ps, encodingArgs);
return Response.ok(stream).build();
} catch (Exception e) {
closeOnException(ps); // wrapper for ps.close();
throw e;
}
}
答案 0 :(得分:0)
您可以添加到方法HttpServletResponse:
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Object streamData(
@PathParam("key") String key,
@Context HttpServletResponse response,
// ... other params
) {
...
response.getOutputStream().write(....)
response.flushBuffer();
response.getOutputStream().close();
return null;
}
答案 1 :(得分:0)
我从dropwizard邮件列表中收到了很好的答案,可以解决我的问题,如果有人遇到相同的问题,我想在此引用。
https://groups.google.com/forum/#!topic/dropwizard-user/62GoLDBrQuo
引用肖恩的回应:
Jersey支持CloseableService,可让您注册在请求完成后要关闭的Closeable对象:
public Response streamData(..., @Context CloseableService closer) {
...
closer.add(closeable);
return Response.ok(...).build();
}