在 OpenLiberty 上使用 Hibernate Envers 设置自定义修订信息



我们正在将应用程序从JEE7迁移到JEE8。 此应用程序依赖于Hibernate-ORM和Hibernate-Envers。在 JEE7 上是版本 5.2.17,在 JEE8 上,两个自由版本现在是 5.4.3。 我们有一个自定义修订实体,它通过 RevisionListener 的实现添加用户信息来扩展 DefaultRevisionEntity。 在JEE7上,它在OpenLiberty 19.0.0.5上运行良好,对于JEE8和Hibernate 5.4.3,我们得到了错误。在 JEE8 和 Hibernate 5.4.3 上,现在可以在修订侦听器上使用 CDI 功能。(使用休眠版本手动设置修订日期)。 在 OpenLiberty 上,当没有 Bean 管理器可供使用时,修订侦听器初始化以某种方式完成,就像下面的堆栈跟踪显示的那样:

Caused by: java.lang.IllegalStateException: org.hibernate.resource.beans.container.internal.NotYetReadyException: CDI BeanManager not (yet) ready to use
[INFO]  at org.hibernate.resource.beans.container.internal.JpaCompliantLifecycleStrategy$BeanImpl.initialize(JpaCompliantLifecycleStrategy.java:112)
[INFO]  at org.hibernate.resource.beans.container.internal.CdiBeanContainerExtendedAccessImpl$BeanImpl.initialize(CdiBeanContainerExtendedAccessImpl.java:113)
[INFO]  at org.hibernate.resource.beans.container.internal.CdiBeanContainerExtendedAccessImpl$BeanImpl.getBeanInstance(CdiBeanContainerExtendedAccessImpl.java:119)
[INFO]  at org.hibernate.resource.beans.internal.ManagedBeanRegistryImpl$ContainedBeanManagedBeanAdapter.getBeanInstance(ManagedBeanRegistryImpl.java:139)
[INFO]  at org.hibernate.envers.internal.revisioninfo.DefaultRevisionInfoGenerator.generate(DefaultRevisionInfoGenerator.java:77)
[INFO]  at org.hibernate.envers.internal.synchronization.AuditProcess.getCurrentRevisionData(AuditProcess.java:133)
[INFO]  at org.hibernate.envers.internal.synchronization.AuditProcess.executeInSession(AuditProcess.java:115)
[INFO]  at org.hibernate.envers.internal.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:174)
[INFO]  at org.hibernate.envers.internal.synchronization.AuditProcessManager$1.doBeforeTransactionCompletion(AuditProcessManager.java:47)
[INFO]  at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:954)
[INFO]  ... 20 more
[INFO] Caused by: org.hibernate.resource.beans.container.internal.NotYetReadyException: CDI BeanManager not (yet) ready to use
[INFO]  ... 31 more
[INFO] Caused by: java.lang.NullPointerException
[INFO]  at org.hibernate.resource.beans.container.internal.JpaCompliantLifecycleStrategy$BeanImpl.initialize(JpaCompliantLifecycleStrategy.java:109)
[INFO]  ... 29 more

我发现这 https://discourse.hibernate.org/t/beanmanager-createinstance-being-called-before-afterbeandiscovery-event-fired/2239 对话可能指向同一个方向。

实际上,这是我们在服务器.xml中设置的功能。

<featureManager>
<feature>jaxrs-2.1</feature> 
<feature>jsonp-1.1</feature>
<feature>cdi-2.0</feature>
<feature>jpaContainer-2.2</feature>
<feature>ejbLite-3.2</feature>
<feature>mpMetrics-1.1</feature>
<feature>mpHealth-1.0</feature>
<feature>mpConfig-1.3</feature>
<feature>servlet-4.0</feature>
</featureManager>

如果您需要更多信息,我会提供它们。 这是一个已知问题吗?如果您能为此问题提供提示或解决方案,我将不胜感激。

谢谢。

是的,从我从Hibernate和IBM收到的回复来看,这似乎确实是一个已知问题,正如我在论坛中提到的,我能够在非常有用的Hibernate团队的指导下为该问题开发解决方法。

解决方法是实现org.hibernate.search.hcore.spi.EnvironmentSynchronizer来控制 JPA 初始化何时可以安全地继续,并javax.enterprise.inject.spi.Extension以检测 CDI 何时准备好BeanManager

我用org.hibernate.service.spi.ServiceContributorinteface注册了我的环境同步器实现。 在环境同步器内部,whenEnvironmentReady事件方法传入一个Runnable,该表示负责 JPA 初始化的任务。 这需要推迟到 CDI 完成 Bean 发现,并且BeanManager准备就绪。

我的 CDI 扩展实现等待AfterBeanDiscovery事件方法,这是允许之前延迟的 JPA 初始化任务成功继续的合适时机。

在我有了解决方法之后,我开始与 IBM 支持部门进行沟通,以提高对兼容性问题的认识,并查看是否可以在将来的发行版中将这种对 Hibernate 初始化的细粒度控制内置到 WebSphere Liberty 中。 IBM表示,他们希望Hibernate能够与WebSphere一起开箱即用,这太棒了,所以我希望我们能在不久的将来看到WebSphere Liberty中对最新版本的Hibernate的全面支持。

更新:我刚刚确认,不幸的是,我们的环境同步器实现不会延迟Envers初始化。 Envers 初始化仍然在 WebSphere 中启动时崩溃,我们的解决方法已经到位。

我将更新我们与 IBM 的案例以包含 Envers,并在 Hibernate 论坛中的线程中添加注释,以查看是否有任何可用的即时选项。

更新:这是我使用Hibernate Envers和自定义RevisionListener测试的解决方案。 将其添加到持久性.xml将允许 WebSphere 成功启动:

<property name="hibernate.delay_cdi_access" value="true"/>

Steve Ebersole的评论:

这个选项 (2) 本质上告诉 Hibernate 延迟访问 BeanManager,直到它第一次需要哪个是在运行时。换句话说,第一次执行需要特定 CDI Bean Hibernate 的操作时,会向 BeanManager 请求它。这有一个严重的缺点,因为如果 bean 不存在,您将在运行时之前(可以想象在部署后的几个月)之前不知道这一点。

我们可能会在短期内使用此选项,目的是在 IBM WebSphere 完全支持最新版本的 Hibernate 开箱即用后将其删除。

最新更新