Tomcat启动时修复OmniFaces BeanManager初始化问题

时间:2016-09-01 09:06:37

标签: jsf cdi tomcat8 omnifaces

我们最近转移到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资源可能未正确配置。 (Markt的)

我不知道Tomcat更改日志中报告的此Web应用程序初始化阶段问题是否可能与我们遇到的问题相关联。从上下文中删除BeanManager资源修复问题的原因仍然不清楚。

有什么想法吗?

1 个答案:

答案 0 :(得分:4)

  

javax.naming.NamingException:WELD-001300:无法找到BeanManager

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

这确实匹配Tomcat 8.5.4中的described change

  

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

我不能告诉Mark Thomas这个决定的推理,并且它背后也没有问题链接。我猜他试图避免由潜在的初始化排序问题导致的间歇性破坏部署导致的混乱行为。这可能是一件好事,但我认为Mark实际上忽略了通过<ordering>web.xml文件中的web-fragment.xml元素定义初始化顺序的可能性。我确实记得Tomcat从来没有尊重这个@WebListener的注释顺序 - 带注释或编程创建的实例(但它对于<listener>声明的实例这样做了)。也许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初始化已根据issue 281进行了重新设计和改进,描述了CDI 1.0向1.1的迁移。 OmniFaces不再使用JNDI来检查BeanManager。 OmniFaces现在将使用CDI 1.1引入的CDI API。

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

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

OmniFaces 2.5尚未最终确定,但截至昨天,Maven中心仍然提供2.5-RC1。