为什么抛出EJBException是一种"推荐"的做法?

vin*_*y_g 11 java ejb java-ee

我一遍又一遍地从许多开发者那里得到这个"建议".根据我的经验,我发现EJBExceptions非常适合从bean实例的角度来看"世界末日"(比如当某些东西错误以至于bean实例无法自行恢复时).如果一个实例可以恢复,我认为最好抛出一个应用程序异常.

这是我一遍又一遍地遇到的模式:

private SomeResource resource;
ejbCreate:
    resource = allocateResource(...);

omMessage:
    try {
    ...
    } catch (JMSException e) {
        throw new EJBException(e);
    }

ejbRemove:
    freeResource(resource);

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

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

这是否是反对抛出EJBException的相关示例?应该抛出EJBException的相关案例是什么?

djn*_*jna 7

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

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

我的经验是,由于缺乏防御性编码,出现了许多棘手的问题."情况X不能出现在一个表现良好的系统中,如果确实存在,那么整个系统就会崩溃,所以我不会为这种可能性编码." 然后我们得到一些"有趣"的星星对齐和操作员错误,并且"不可能发生"连续几次发生,并且意外的副作用开始导致真正难以诊断问题.

因此我会说:

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