3

我最近惊讶地发现这个播放框架控制器动作代码中的 finally 块仅在异常之后被调用,但在调用实际成功时从未被调用。

try {
    InputStream is = getInputStreamMethod();
    renderBinary(is, "out.zip");
catch (Exception e) {
    e.printStackTrace();
} finally {
    cleanUp();
}

当调用 renderBinary() 时,线程可能被终止或发生了什么,但对我来说,这是不直观的。我怀疑其他 render() 调用也会发生同样的事情,但我没有验证它。

我通过将 renderBinary() 移到 try/catch 之后解决了这个问题。进一步的调查显示 play 提供了一个 @Finally 注释来创建一个在控制器操作执行后执行的方法。这里需要注意的是,这将在控制器中执行任何操作后被调用,因此它可能并不总是一个好的选择。

我的问题是:为什么 finally 块在 renderBinary() 之后没有被执行,这在任何地方都有记录吗?我在播放文档中找不到任何参考。

为了阐明导致这一发现的事件顺序:

  1. 由于 finally 块而应该被删除的文件没有被删除。

  2. 考虑到它不可能是由非执行 finally 块引起的,我更改了方法以使用 Amazon SQS 消息队列在 finally 块中发送消息——一个单独的作业接收消息并删除相关文件。

  3. 消息没有被发送。

  4. 我在代码中设置断点并确定正在调用 renderBinary,但 finally 块没有被执行。

  5. 为了安全起见,我在 finally 子句中添加了日志消息,但这些也不存在。

  6. 我重复了几次调试练习,每次都没有执行 finally 子句。

(请注意,实际代码并不像上面那样。这是一个非常简化的示例,只是为了说明情况。)

4

1 回答 1

4

这是真的。我今天才发现这一点,因为我的公司使用了该play框架并且有人遇到了它。

据我了解,这可能只发生在play2.0 之前的版本中,但是当您在渲染调用之后捕获所有异常时,play显然会重写代码以跳过该finally块......

我不明白为什么或究竟如何做到这一点,但显然是这样。

如果你捕捉到一个特定的异常,我认为这不会发生。

但是,是的,你不是疯子或糟糕的程序员。这真的只是一个奇怪的、无证的play陷阱。

于 2014-04-29T22:52:45.017 回答