为什么在playframework renderbinary之后最终没有阻止执行?

时间:2014-01-23 16:10:44

标签: java playframework try-catch-finally finally try-finally

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

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

也许线程被终止或调用renderBinary()时的某些东西,但对我来说,它是非直观的。我怀疑其他render()调用会发生同样的事情,但我没有验证它。

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

我的问题是:为什么finally块不会在renderBinary()之后执行,并且在任何地方记录?我在剧本文档中找不到任何引用。

澄清导致此发现的事件顺序:

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

  2. 认为它不可能是由非执行的finally块引起的,我改变了方法,使用Amazon SQS Messaging Queue在finally块中发送消息 - 一个单独的作业收到消息并删除相关文件。

  3. 邮件未发送。

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

  5. 为了安全起见,我在finally子句中添加了日志消息,这些消息也没有出现。

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

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

1 个答案:

答案 0 :(得分:4)

这是真的。我今天刚刚发现了这个问题,因为我的公司使用play框架,有人碰到了它。

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

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

如果你发现了一个特定的例外情况,我认为这不会发生。

但是,是的,你不是疯了,也不是坏程序员。这真的只是一个奇怪的,没有记载的finally陷阱。