【问题标题】:Why throwing an EJBException is a "recommended" practice?为什么抛出 EJBException 是“推荐”的做法?
【发布时间】:2009-10-17 06:46:51
【问题描述】:

我不断地从许多其他开发人员那里得到这个“建议”。根据我的经验,我发现从 bean 实例的角度来看,EJBExceptions 非常适合“世界末日”(比如当某些事情非常错误以至于 bean 实例无法自行恢复时)。如果一个实例可以恢复,我认为最好抛出一个应用程序异常。

这是我一次又一次遇到的模式:

私有 SomeResource 资源; ejb创建: 资源 = 分配资源(...); om消息: 尝试 { ... } 捕捉(JMSException e){ 抛出新的 EJBException(e); } ejb删除: 免费资源(资源);

恕我直言,这是导致资源泄漏的反模式。

编辑:具体来说,EJB 规范说,如果 bean 从业务方法中抛出运行时异常(并且 EJBException 是运行时异常),那么 bean 会被丢弃而不调用 ejbRemove。

这是一个反对抛出 EJBException 的相关示例吗? 应该抛出 EJBException 的相关情况有哪些?

【问题讨论】:

  • @vinny_g:我已经添加了您对我(现已删除)“答案”的评论中的解释。

标签: java jakarta-ee ejb


【解决方案1】:

在 EJB 无法从遇到的异常中恢复的情况下,EJB 规范(EJB 3 中的 14.2.2)建议抛出 EJBException。该规范还说,EJB 可以合理地允许(未经检查的)系统异常传播到容器。

我同意您对规范的阅读,即在这种情况下,容器不会调用生命周期回调方法,因此您担心通常在 ejbRemove() 回调中发生的任何资源整理不会发生,因此存在资源泄漏的危险。

我的经验是,由于缺乏防御性编码,会出现很多棘手的问题。 “情况 X 不可能发生在一个表现良好的系统中,如果发生了,那么整个系统就会被破坏,所以我不会为这种可能性编写代码。”然后我们得到一些“有趣”的星星对齐和操作员错误,“不可能发生”快速连续发生几次,并且意外的副作用会导致非常难以诊断的问题。

因此我会说:

  1. 尽一切可能使 Bean 实例处于下一次调用业务方法可能能够工作的状态。这可能意味着捕获异常并关闭错误的资源。在这种情况下,您可能会选择告诉调用者,“对不起,老大,该请求不起作用,但如果您稍后重试......”我会通过抛出 TransientException 已检查异常来做到这一点。
  2. 如果您在ejbRemove 中没有重要的内务管理,那么您可以允许 SystemExceptions 传播 - 但我不确定这是否友好。您依赖于一个库,它会抛出一个NullPointerException。实际上是更强大的捕获和重新抛出TransientException
  3. 如果您确实有重要的内务管理,那么我认为您确实需要捕获所有异常并至少尝试清理。然后,您可以选择重新抛出 EJBException 或系统异常,以便销毁实例,但至少您已尝试进行内务处理。

【讨论】:

    【解决方案2】:

    即使 EJB 方法抛出了应用程序异常,容器仍然可以提交当前事务。如果您的 EJB 方法可以抛出应用程序异常,那么您应该考虑像这样使用 EJBContext.setRollbackOnly():

    public void method() throws ApplicationException {
        try {
        ...
        } catch (ApplicationException e) {
            _context.setRollbackOnly();
            throw e;
        }
    }
    

    抛出 EJBException 或系统(未经检查的)异常意味着容器将自动回滚事务。见:http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html

    如果您系统的 EJB 不定期捕获和处理应用程序异常,则抛出异常的代码可能会导致提交更改的部分完成操作。

    这可能导致难以发现的错误,因为带有 CMP 的 EJB 方法的“用户神话”是它映射到一个原子事务。部分完整的业务逻辑以原子方式提交给数据库。当它在实践中发生时,这是非常令人困惑的。 Joel 关于泄漏抽象的文章:http://www.joelonsoftware.com/articles/LeakyAbstractions.html 解释了原因。

    如果您的系统具有无法正确处理应用程序异常的 EJB,则合乎逻辑的答案是修复它们,以便它们能够正确处理。在问题得到解决之前,您的团队可能有合理的理由不希望从 EJB 中抛出应用程序异常。

    【讨论】:

      【解决方案3】:

      是否泄漏资源取决于这些资源的管理方式。丢弃的 bean 得到垃圾收集,放弃它对​​资源的引用,当没有更多引用指向它时,依次收集垃圾。如果资源还保存在具有根路径的集合中,它将泄漏,除非容器具有可以检测空闲资源并回收它的池管理器。

      我同意你的观点,bean 应该自己处理任何异常,并让调用者知道结果。对我来说,您描述的情况下的反模式是使用异常来传递对象状态。异常应该是异常,不能作为返回值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-19
        • 2010-10-09
        • 2014-06-20
        相关资源
        最近更新 更多