我最近惊讶地发现,这个 play 框架 Controller 操作代码中的 finally block 只在异常之后被调用,但从未在调用真正成功时被调用。
try {
InputStream is = getInputStreamMethod();
renderBinary(is, "out.zip");
catch (Exception e) {
e.printStackTrace();
} finally {
cleanUp();
}
当调用 renderBinary() 时,可能线程终止或其他原因,但对我来说,这是不直观的。我怀疑其他 render() 调用也会发生同样的事情,但我没有验证。
我通过将 renderBinary() 移动到 try/catch 之后解决了这个问题。进一步的调查显示,play 提供了一个 @Finally 注释来创建一个在 Controller 操作执行后执行的方法。这里需要注意的是,这将在 Controller 中执行任何操作后被调用,因此它可能并不总是一个好的选择。
我的问题是:为什么 finally block 在 renderBinary() 之后没有执行,这在任何地方都有记录吗?我在 Play 文档中找不到任何引用。
阐明导致这一发现的事件顺序:
由于 finally block 而应该删除的文件没有被删除。
认为这不可能是由未执行的 finally block 引起的,我更改了使用 Amazon SQS Messaging Queue 在 finally block 中发送消息的方法——一个单独的作业接收消息并删除相关文件。
消息未发送。
我在代码中设置了断点并确定正在调用 renderBinary,但 finally block 没有被执行。
为了安全起见,我在 finally 子句中添加了日志消息,但这些消息也不存在。
我重复调试了几次,每次都没有执行 finally 子句。
(请注意,实际代码与上面的代码并不完全相同。这是一个非常简化的示例,只是为了说明情况。)
最佳答案
这是真的。我今天才知道这个,因为我的公司使用play
框架,有人遇到了它。
据我了解,这可能只发生在 2.0 之前的 play
版本中,但是当您在渲染调用后捕获所有异常时,play
显然会将代码重写为跳过 finally
block ...
我不明白这是为什么或具体是如何完成的,但显然是这样。
如果你捕捉到一个特定的异常,我认为这不会发生。
但是,是的,您既不是疯子也不是糟糕的程序员。这真的只是一个奇怪的、未记录的 play
问题。
关于java - 为什么 finally 在 playframework renderbinary 之后不阻止执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21313512/