EJB3.1系统exception与javax.ejb.EJBException

在提出我的问题之前,只是关于EJB3.1exception的一些背景知识 –

应用程序例外包括

  • 用户定义的具有@ApplicationException注释的已检查或未检查的exception

  • 所有已检查的例外

    java.lang.Exception&它的子类exception
    除了java.rmi.RemoteException和它的子类exception

系统例外包括

  • java.rmi.RemoteException和它的子类exception

  • 所有未经检查的例外情况

    java.lang.RuntimeException和它的子类exception
    java.lang.Error和它的子类exception

以下是我在本书中读到的声明

在EJB系统中,客户端不会例外,当遇到此类exception时,这些exception不会按原样传递给客户端,而是在javax.ejb.EJBException中包含。

我的问题 –

  1. 上面描述的所有应用程序exception是否应该由EJB直接抛给客户端?
  2. 如果在抛出到客户端之前将系统exception包装在javax.ejb.EJBException中,那么javax.ejb.EJBException是否被视为系统exception?

  1. 是的,或多或少是他们的工作方式。 有关EJB行为的更多详细信息,请查看以下博客文章: 链接

也来自这个问题 :

当出现业务逻辑错误而不是系统错误时,应抛出应用程序exception。

有一个重要的区别:应用程序exception不会自动导致事务回滚。 客户端有机会在抛出应用程序exception后进行恢复。

应用程序exception将发送到客户端,而不会重新打包为EJBException。 因此,您可以使用它们来报告validation错误或业务逻辑问题,并且它们将到达客户端。

  1. javax.ejb.EJBException扩展了RuntimeException所以是的,它是一个系统exception。

与此相关的常见场景:如果您的应用程序代码中有未捕获的RuntimeException ,它将回滚。 这是非常有用的默认行为。

IndoKnight,您对Java EE框架中的Exception语义的完美总结。工作。

以下是两个唯一的“bean提供者”行,您和我需要了解Java EE中的exception:

根据您认为合适的任何类型的exception或错误,您的bean可以完全自由地恢复,相对于bean可能存在的其他约束。 如果你从exception中恢复过来,那么恭喜 – 再也没有问题=)

例如,相关约束可能是“使用容器管理的事务划分的企业bean不得使用任何干扰容器事务划分边界的事务管理方法”来引用Java EE 7教程第48-2页( 您想要吗?)要以编程方式设置容器管理事务的回滚,请使用EJBContext.setRollbackOnly() )。

与任何类型的Java应用程序一样,您也不鼓励处理从非常低级别抛出的ThrowableError 。 理论上, RuntimeException在这个类别中被计算,因为它如此着名地表示“开发者错误”,就像“完全出乎意料” – 但我们都知道它不是。

基本上,一个意外的exception(运行时exception+我们假设来自其他人的其他狗屎)被假定为您的代码无法处理,应该由服务器处理。 服务器需要通过在日志中打印有关它的内容来处理“不可处理的”exception( 参见EJB 3.2规范 ,第204页 )( 稍后我将详细介绍! )。

进一步来说..

你问(这是我相信或坚持的):

上面描述的所有应用程序exception是否应该由EJB直接抛给客户端?

是。 除非您明确声明应该使用ApplicationException的rollback属性,否则不会回滚事务(如果一个处于活动状态)。 抛出exception的Java代码是非常自然的事情。 Java EE无意拆除此编程模型。 所以继续,抛出你喜欢的已检查exception,强制客户端尝试捕获它们或将运行时exception标记为应用程序exception并抛出它们。 快乐投掷!

如果在抛出到客户端之前将系统exception包装在javax.ejb.EJBException中,那么javax.ejb.EJBException是否被视为系统exception?

是的 ,但不是因为你提供的原因。 要清楚,没有名为SystemException的类型。 只是花哨的措辞来描述那些大多数bean没有想到的例外情况,而且最有可能的是,它们来自EJB容器。 您的代码绝对不应该抛出EJBException。 这样做可能只会阻碍服务器的思维。 由于您不拥有代码,因此也不能将exception注释为@ApplicationException,它由Java EE API提供。 您可以扩展EJBException,但将代码伪装成服务器代码库的一部分是没有任何意义的。 最重要的是,由于EJBException扩展了RuntimeException ,我认为将EJBException归类为“系统级exception”是安全的。

留意魔鬼

某些远程客户端将接收RemoteException而不是EJBException。

在一个巨大的企业项目中你甚至可能都没有意识到的拦截器 ,可能会吞下从你的方法抛出的exception,即使你从来没有计划让他这样做,也会提交活动事务。

我敢打赌,您认为使用Throwable.getCause()始终可以检索到被抑制的exception 。 请注意, EJB 3.2规范并未说容器必须或应该保留对被抑制原因的引用。 事实上,容器唯一要做的就是记录exception。 然后,如果bean不是单例,则必须丢弃bean实例并且不再使用它。 此外,如果bean是一个消息驱动的bean,那么只有这样才能被“包装”。 未指定如何“包装”exception。 超级便携式酷代码也应该看看Throwable.getCause()方法和Throwable.getSuppressed() 。 不要盲目期望在处理代码中始终找到原始exception。

返回void的异步方法( 注释为@Asynchronous的公共会话bean方法 )不能将exception传播到其客户端。 因此,它们不得声明或抛出应用程序exception( 请参阅EJB 3.2规范第82页 )。 请注意,当您调用异步方法时,可能是服务器无法提供线程资源来为您的请求提供服务,如果是这样,他需要抛出一个.. EJBException( 第48页 )!