在 JavaEE 6 的 @PostConstruct 中出现异常后是不是调用了 @PreDestroy?
Posted
技术标签:
【中文标题】在 JavaEE 6 的 @PostConstruct 中出现异常后是不是调用了 @PreDestroy?【英文标题】:Is @PreDestroy called after an exception in @PostConstruct in JavaEE 6?在 JavaEE 6 的 @PostConstruct 中出现异常后是否调用了 @PreDestroy? 【发布时间】:2013-01-13 23:57:35 【问题描述】:目前,我们在 JavaEE 6 上的 @PostConstruct 方法中遇到了一个更复杂的初始化问题。有几个地方可能会出错并且可能会出现异常。在那种情况下,我们可能有一个半初始化的 bean。
在这种情况下会调用@PreDestroy 方法吗?我们可以在那里检查我们的资源并在必要时释放它们。还是我们需要在@PostConstruct 中捕获所有异常并清理那里的所有内容?规范对此并不清楚(或者我可能没有找到)。
或者,由于缺乏规范,它是特定于供应商的吗?在 JBoss 7.x 上怎么样?
【问题讨论】:
【参考方案1】:我认为 EJB3.1 规范在这种情况下很明确:如果您在 PostConstruct 中获取了非托管资源,那么您必须自己释放它们以防异常。
第 14.3.3 节 - 会话 Bean 的 PostConstruct 和 PreDestroy 方法的异常 容器操作:记录异常或错误。 如果是 Singleton,则回滚任何容器启动的事务。 丢弃实例。
第 14.3.11 节 - 资源释放 当容器因为系统异常而丢弃实例时,容器应该释放实例持有的所有资源,这些资源是通过企业 bean 环境中声明的资源工厂获取的(参见第 16.7 小节)。
注意:虽然容器应该释放实例通过企业 bean 环境中声明的资源工厂获取的资源管理器的连接,但容器通常不能释放实例可能通过其获取的“非托管”资源JDK API。例如,如果实例打开了 TCP/IP 连接,大多数容器实现将无法释放连接。连接最终会被JVM垃圾回收机制释放。
以下 2 节指定当在 EJB 业务方法或 @PostContruct 内部发生 RuntimeException 时不调用 @PreDestroy 方法:
4.7.3 处理异常 不是从企业 bean 类的任何方法(包括业务方法和容器调用的生命周期回调拦截器方法)抛出的不是应用程序异常的 RuntimeException 会导致转换到“不存在”状态。异常处理在第 14 章中有详细描述。请参阅第 12.5.1 节了解与生命周期回调拦截器方法有关的规则,当多个此类方法应用于 bean 类时。 从客户端的角度来看,会话对象继续存在。客户端可以继续访问会话对象,因为容器可以将客户端的请求委托给另一个实例。
12.5.1异常 生命周期回调拦截器方法可能会抛出系统运行时异常,但不会抛出应用程序异常。 任何生命周期拦截器回调方法抛出的运行时异常都会导致 bean 实例及其拦截器在拦截器链展开后被丢弃 [59]。 当 bean 和拦截器因此类异常而被丢弃时,不会调用 PreDestroy 回调:链中的生命周期回调拦截器方法应在拦截器链展开时执行任何必要的清理操作。
【讨论】:
是的,这很清楚,但它没有回答我的问题(或者我可能不明白你的回答)。我在@PostConstruct 中获得的所有内容,我都必须负责发布。这是肯定的,毫无疑问。问题是:我可以在@PreDestroy 中做到这一点吗?规格不清楚。容器从“不存在”状态进入“方法就绪池”。当转换无法执行时,究竟会发生什么?转换解释得很好,但没有解释错误场景。以上是关于在 JavaEE 6 的 @PostConstruct 中出现异常后是不是调用了 @PreDestroy?的主要内容,如果未能解决你的问题,请参考以下文章
Maven:javaee-api 与 jboss-javaee-6.0