【问题标题】:fixing OmniFaces BeanManager initialization issues when Tomcat starts修复 Tomcat 启动时的 OmniFaces BeanManager 初始化问题
【发布时间】:2016-09-01 09:06:36
【问题描述】:

我们最近迁移到 Tomcat 8.5.4(从 8.5.3)和 Omnifaces 2.4(从 2.3),我们还在 Web 应用程序中进行了一些更改。从那以后,我们的 Web 应用程序不再启动,日志中出现以下异常:

Exception sending context initialized event to listener instance of class org.omnifaces.ApplicationListener

java.lang.ExceptionInInitializerError
at org.omnifaces.ApplicationListener.checkCDIAvailable(ApplicationListener.java:77)
at org.omnifaces.ApplicationListener.contextInitialized(ApplicationListener.java:61)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4716)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5178)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:152)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1403)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

Caused by: java.lang.IllegalStateException: CDI BeanManager instance is not available in JNDI.
at org.omnifaces.config.BeanManager.<init>(BeanManager.java:100)
at org.omnifaces.config.BeanManager.<clinit>(BeanManager.java:49)
... 11 more

Caused by: java.lang.IllegalStateException: javax.naming.NamingException: WELD-001300: Unable to locate BeanManager
at org.omnifaces.util.JNDI.lookup(JNDI.java:95)
at org.omnifaces.config.BeanManager.<init>(BeanManager.java:96)
... 12 more

Caused by: javax.naming.NamingException: WELD-001300: Unable to locate BeanManager
at org.jboss.weld.resources.ManagerObjectFactory.getObjectInstance(ManagerObjectFactory.java:62)
at org.apache.naming.factory.FactoryBase.getObjectInstance(FactoryBase.java:94)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:321)
at org.apache.naming.NamingContext.lookup(NamingContext.java:840)
at org.apache.naming.NamingContext.lookup(NamingContext.java:160)
at org.apache.naming.NamingContext.lookup(NamingContext.java:828)
at org.apache.naming.NamingContext.lookup(NamingContext.java:160)
at org.apache.naming.NamingContext.lookup(NamingContext.java:828)
at org.apache.naming.NamingContext.lookup(NamingContext.java:174)
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:163)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at org.omnifaces.util.JNDI.lookup(JNDI.java:90)
... 13 more

Exception sending context initialized event to listener instance of class com.sun.faces.config.ConfigureListener

java.lang.RuntimeException: java.lang.NoClassDefFoundError: Could not initialize class org.omnifaces.config.BeanManager
at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:292)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4714)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5178)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:152)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1403)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.omnifaces.config.BeanManager
at org.omnifaces.util.Beans.getManager(Beans.java:88)
at org.omnifaces.util.Beans.getReference(Beans.java:113)
at org.omnifaces.application.OmniApplication.<init>(OmniApplication.java:70)
at org.omnifaces.application.OmniApplicationFactory.createOmniApplication(OmniApplicationFactory.java:89)
at org.omnifaces.application.OmniApplicationFactory.getApplication(OmniApplicationFactory.java:54)
at com.sun.faces.application.InjectionApplicationFactory.getApplication(InjectionApplicationFactory.java:93)
at com.sun.faces.config.InitFacesContext.getApplication(InitFacesContext.java:142)
at com.sun.faces.lifecycle.ClientWindowFactoryImpl.<init>(ClientWindowFactoryImpl.java:62)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at javax.faces.FactoryFinderInstance.getImplGivenPreviousImpl(FactoryFinderInstance.java:405)
at javax.faces.FactoryFinderInstance.getImplementationInstance(FactoryFinderInstance.java:251)
at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:543)
at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:283)
at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:328)
at com.sun.faces.config.processor.FactoryConfigProcessor.process(FactoryConfigProcessor.java:236)
at com.sun.faces.config.ConfigManager.initialize(ConfigManager.java:439)
at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:227)

我们的配置:

  • Tomcat 8.5.4
  • CDI Weld 2.3.5.Final
  • JSF 2.2.13
  • Omnifaces 2.4
  • Primefaces 6.0
  • WEB-INF 中的一个空 beans.xml 文件
  • 根 Web 应用程序上下文中的 BeanManager 资源条目
  • Tomcat 由我们的 Java 代码启动(嵌入式使用)。

BeanManager 资源条目:

<Resource name="BeanManager"
          auth="Container"
          type="javax.enterprise.inject.spi.BeanManager"
          factory="org.jboss.weld.resources.ManagerObjectFactory"/>

我们已移回 Tomcat 8.5.3 和 omnifaces 2.3,并尝试了组件版本的不同组合(8.5.3 与 2.4、8.5.4 与 2.3 等...)以确定根本原因的问题,但无济于事。

最后,我们怀疑所有这些组件(Tomcat、Weld、Onmnifaces,...)的初始化之间存在竞速条件问题。

最后,我从上下文 XML 文件中删除了 BeanManager 资源条目。

从上下文中移除:

<Resource name="BeanManager"
          auth="Container"
          type="javax.enterprise.inject.spi.BeanManager"
          factory="org.jboss.weld.resources.ManagerObjectFactory"/>

它解决了问题。

我查看了 Tomcat 8.5.4 的更改日志,我可以找到这个更改:

不要尝试在 Web 应用程序的初始化阶段启动 Web 资源,因为此时 Web 应用程序尚未完全配置,并且 Web 资源可能未正确配置。 (市场)

我不知道 Tomcat 更改日志中报告的此 Web 应用程序的初始化阶段问题是否与我们遇到的问题有关。从上下文中移除 BeanManager 资源解决问题的原因仍不清楚。

有什么想法吗?

【问题讨论】:

  • 我可以解释 OmniFaces 2.4 中 的(非)必要性,但你能试试 OmniFaces 2.5-SNAPSHOT 吗?在该版本中,几乎所有 CDI 初始化都进行了重新设计/改进:github.com/omnifaces/omnifaces/issues/281,它对我来说效果很好。
  • 使用 8 月 31 日构建的 omnifaces-2.5 快照版本,我们的 Web 应用程序正确启动,无论是否将 条目添加到 Web 上下文。但是,我很想知道为什么我们必须在 2.4 版本中删除 条目:)
  • 好的,你能说出异常的根本原因吗?
  • 很遗憾没有。我感觉这是一个竞争条件问题,好像omnifaces 试图在将bean 管理器实际添加到JNDI 之前访问它。事实是,omnifaces 2.5 的最新快照没有问题,当且仅当我不在 Web 应用程序的上下文中添加 条目时,omnifaces 2.4 也没有问题。
  • 堆栈跟踪中没有根本原因?那很奇怪。应该有一个 IllegalArgumentException 指示初始化失败的确切原因。

标签: jsf cdi tomcat8 omnifaces


【解决方案1】:

javax.naming.NamingException: WELD-001300: 无法定位 BeanManager

这基本上意味着找到了BeanManager JNDI 资源定义(在context.xml 中定义),但尚未创建JNDI 资源后面的具体BeanManager 实例。

这确实与 Tomcat 8.5.4 中的 described change 匹配。

不要尝试在 Web 应用程序的初始化阶段启动 Web 资源,因为此时 Web 应用程序尚未完全配置,并且 Web 资源可能未正确配置。 (市场)

我无法说出Mark Thomas 做出这个决定的原因,而且它背后也没有问题链接。我猜他试图避免由潜在的初始化排序问题引起的间歇性中断部署引起的混乱行为。这也许是件好事,但我认为 Mark 实际上忽略了通过 web.xmlweb-fragment.xml 文件中的 &lt;ordering&gt; 元素定义初始化顺序的可能性。我确实记得 Tomcat 从未尊重过 @WebListener-annotated 或以编程方式创建的实例的调用顺序(但是它对 &lt;listener&gt; 声明的实例这样做)。或许 Mark 应该更好地修复该部分,而不是在初始化阶段完全禁用 JNDI。

关于 OmniFaces 2.4 中的更改,根据issue 243,此版本添加了对特定于 Weld 的 servlet 上下文属性的回退。这将在 JNDI 资源不存在并且 Weld 用作 CDI 实现时使用。也就是说,Weld 在内部也将 BeanManager 实例存储为 servlet 上下文属性,因此 OmniFaces 可以直接获取它,而无需 JNDI。这意味着,context.xml 不再需要。在 Tomcat 8.5.4 中,您实际上也应该删除 context.xml,因为 OmniFaces 2.4 仍然首先尝试检查 JNDI 资源,这最终会引发异常,因为 BeanManager 实例由于 Tomcat 8.5.4 意外不可用改变。

在 OmniFaces 2.5 中,CDI 初始化已按照描述 CDI 1.0 到 1.1 的迁移的 issue 281 进行了重新设计和改进。 OmniFaces 不再使用 JNDI 来检查 BeanManager。 OmniFaces 现在将使用 CDI 1.1 引入的 CDI API。

BeanManager beanManager = CDI.current().getBeanManager();

无论 JNDI 配置/初始化如何,这都有效。

OmniFaces 2.5 尚未最终确定,但 2.5-RC1 已于昨天在 Maven 中心提供。

【讨论】:

  • 更多理由“只”使用 JEE 容器,而不是试图将所有内容都包含在一个普通的 servlet 容器中。
  • 感谢 BalusC 的分析。我将使用 Omnifaces 2.4(它是对 JSF 的一个很好的补充),并从上下文中删除资源。我同意 Kukeltje 的观点,但有时我们必须维护旧代码,或者升级普通 JEE 容器的某些部分:)
  • 既然您是新来的,请不要忘记将答案标记为已接受,只要它有助于(最)理解和解决问题。另见How does accepting an answer work?
猜你喜欢
  • 2022-01-12
  • 1970-01-01
  • 2019-09-22
  • 1970-01-01
  • 2010-12-21
  • 2015-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多