使用嵌入式Jetty 12部署Mojarra 4.0时出现CDI不可用异常
环境与配置
我使用Java 21.0.7 + 嵌入式Jetty 12.0.22运行Jakarta Faces 4.0(Mojarra 4.0.11),因Jetty暂不满足Mojarra 4.1所需的Jakarta EE 11要求。采用无web.xml的编程式配置:
var servletContext = new ServletContextHandler("/", true, false); var facesServlet = new ServletHolder("facesServlet", jakarta.faces.webapp.FacesServlet.class); servletContext.addServlet(facesServlet, "*.xhtml"); servletContext.addEventListener(new com.sun.faces.config.ConfigureListener()); servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", "true");
启动异常
启动时抛出如下异常:
Exception in thread "main" java.lang.IllegalStateException: CDI is not available
at com.sun.faces.util.Util.getCdiBeanManager(Util.java:1526)
at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:126)
at org.eclipse.jetty.ee10.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:1591)
at org.eclipse.jetty.ee10.servlet.ServletContextHandler.contextInitialized(ServletContextHandler.java:500)
at org.eclipse.jetty.ee10.servlet.ServletHandler.initialize(ServletHandler.java:676)
at org.eclipse.jetty.ee10.servlet.ServletContextHandler.startContext(ServletContextHandler.java:1325)
at org.eclipse.jetty.ee10.servlet.ServletContextHandler.lambda$doStart$0(ServletContextHandler.java:1051)
at org.eclipse.jetty.server.handler.ContextHandler$ScopedContext.call(ContextHandler.java:1463)
at org.eclipse.jetty.ee10.servlet.ServletContextHandler.doStart(ServletContextHandler.java:1048)
已尝试的操作
- 类路径添加以下JAR:
- jakarta.faces.4.0.11.jar
- weld-servlet-shaded-4.0.3.Final.jar
- jakarta.servlet.jsp.jstl-api-2.0.0.jar
- 使用Jetty EE10版本JAR(包含jetty-ee10-cdi-12.0.22.jar),确保使用jakarta.enterprise.cdi-api-4.0.1.jar而非3.0.1版本
- 在webapp资源文件夹添加空的
beans.xml:
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd" bean-discovery-mode="annotated" version="4.0"></beans>
请问需要补充或修改哪些配置才能让Jakarta Faces 4.0在嵌入式Jetty 12上正常运行?
1. 手动启用Jetty的CDI集成
嵌入式Jetty默认不会自动初始化CDI容器,需显式配置Jetty的CDI组件并集成Weld:
Server server = new Server(8080); ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/"); // 添加Jetty CDI核心组件 CdiDecorator cdiDecorator = new CdiDecorator(); context.addDecorator(cdiDecorator); context.addEventListener(new CdiInitializer()); // 配置Weld初始化监听器 Weld weld = new Weld(); context.addEventListener(new WeldInitialListener(weld)); context.setInitParameter("org.jboss.weld.environment.servlet.javax.enterprise.inject.spi.BeanManager", "true");
2. 调整Mojarra的CDI相关配置
Mojarra 4.0要求CDI容器在自身初始化前就绪,需做以下调整:
- 移除手动添加的
ConfigureListener,让Weld自动扫描并初始化它(若项目无CDI注解类,将beans.xml的bean-discovery-mode改为all) - 添加Mojarra的CDI启用参数:
context.setInitParameter("com.sun.faces.cdi.enableCDI", "true"); context.setInitParameter("jakarta.enterprise.inject.spi.BeanManager", "java:comp/BeanManager");
3. 确保依赖无冲突
- 彻底移除任何旧版Jakarta EE API JAR(如jakarta.enterprise.cdi-api 3.x)
- 确认
weld-servlet-shaded-4.0.3.Final.jar包含完整Weld运行时依赖,无需额外添加其他Weld模块
4. 完整配置示例
public static void main(String[] args) throws Exception { Server server = new Server(8080); ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/"); context.setResourceBase("src/main/webapp"); // 设置webapp资源目录 // 配置CDI CdiDecorator cdiDecorator = new CdiDecorator(); context.addDecorator(cdiDecorator); context.addEventListener(new CdiInitializer()); Weld weld = new Weld(); context.addEventListener(new WeldInitialListener(weld)); context.setInitParameter("org.jboss.weld.environment.servlet.javax.enterprise.inject.spi.BeanManager", "true"); // 配置Faces Servlet ServletHolder facesServlet = new ServletHolder(FacesServlet.class); context.addServlet(facesServlet, "*.xhtml"); // Mojarra核心配置 context.setInitParameter("com.sun.faces.forceLoadConfiguration", "true"); context.setInitParameter("com.sun.faces.cdi.enableCDI", "true"); context.setInitParameter("jakarta.enterprise.inject.spi.BeanManager", "java:comp/BeanManager"); server.setHandler(context); server.start(); server.join(); }
关键说明
- Jetty 12 EE10的CDI支持需显式添加
CdiInitializer和CdiDecorator来启用容器级集成 WeldInitialListener必须优先于Mojarra的配置监听器执行,通过Jetty监听器加载顺序或自动扫描保证- 若项目无自定义CDI Bean,
beans.xml的bean-discovery-mode设为all可确保Mojarra内部类被CDI容器识别
内容的提问来源于stack exchange,提问作者dannerfr

