【问题标题】:Why doesn't finally block execute after playframework renderbinary?为什么在playframework renderbinary之后最终不阻止执行?
【发布时间】:2023-03-15 04:45:01
【问题描述】:

我最近惊讶地发现这个播放框架控制器动作代码中的 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 子句。

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

【问题讨论】:

  • 我所知道的唯一可以阻止 finally 运行的是System.exit()、JVM 崩溃或中断线程。 renderBinary() 是否有任何你知道的线程停止?
  • 我不知道。这就是我希望有人能回答的问题。当它发生时,我感到非常惊讶——最终我们的云服务器上出现了一堆本应被删除的文件!
  • 当文件没有被删除时,我通过断点确定finally子句没有被执行。不过感谢您的意见。
  • 但是您是否也验证过您的try 块是否已完成?这是没有执行finally 块的主要原因。除了代码永远挂起的可能性,正如 CodeChimp 已经说过的那样,JVM 终止也可能阻止 finally 块的执行。
  • 我在上面的消息中添加了导致此发现的步骤。 try 发生了,renderBinary 发生了,finally 没有发生。

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


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 哇,真的有人验证了这个,太好了!!我们使用的是 v1.2,所以这是有道理的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-28
  • 1970-01-01
相关资源
最近更新 更多