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中包含。
我的问题 –
- 上面描述的所有应用程序exception是否应该由EJB直接抛给客户端?
- 如果在抛出到客户端之前将系统exception包装在javax.ejb.EJBException中,那么javax.ejb.EJBException是否被视为系统exception?
- 是的,或多或少是他们的工作方式。 有关EJB行为的更多详细信息,请查看以下博客文章: 链接
也来自这个问题 :
当出现业务逻辑错误而不是系统错误时,应抛出应用程序exception。
有一个重要的区别:应用程序exception不会自动导致事务回滚。 客户端有机会在抛出应用程序exception后进行恢复。
应用程序exception将发送到客户端,而不会重新打包为EJBException。 因此,您可以使用它们来报告validation错误或业务逻辑问题,并且它们将到达客户端。
-
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应用程序一样,您也不鼓励处理从非常低级别抛出的Throwable
或Error
。 理论上, 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页 )!