JSF 2.3配置禁用CDI后仍报找不到CDI BeanManager如何解决
正在将JSF 1.1项目升级至JSF 2.3,项目使用JSP作为视图技术,运行环境为Tomcat 9。
项目build.gradle中配置的JSF依赖如下:
api 'org.glassfish:javax.faces:2.3.9'
升级初期希望尽可能减少代码改动,保留原有faces-config.xml配置,让managed-bean继续由JSF管理而非交由CDI托管,同时暂时不启用PARTIAL_STATE_SAVING特性。
已在web.xml中添加如下上下文参数:
<context-param> <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name> <param-value>false</param-value> </context-param> <context-param> <param-name>javax.faces.ENABLE_CDI_RESOLVER_CHAIN</param-name> <param-value>false</param-value> </context-param>
启动Tomcat时抛出如下错误:
javax.faces.FacesException: Unable to find CDI BeanManager at com.sun.faces.el.ELUtils.tryAddCDIELResolver(ELUtils.java:312) at com.sun.faces.el.ELUtils.buildFacesResolver(ELUtils.java:242) at com.sun.faces.application.ApplicationAssociate.initializeELResolverChains(ApplicationAssociate.java:503) at com.sun.faces.application.ApplicationImpl.performOneTimeELInitialization(ApplicationImpl.java:1405) at com.sun.faces.application.ApplicationImpl.getELResolver(ApplicationImpl.java:529)
核心疑问:
- 上述
javax.faces.ENABLE_CDI_RESOLVER_CHAIN=false配置不生效的原因是什么 - 如何在项目中彻底停用CDI,让Bean继续由JSF原生机制托管
- 除了已配置的参数外,还需要补充什么配置
javax.faces.ENABLE_CDI_RESOLVER_CHAIN=false本身就不能完全阻断JSF 2.3的CDI探测逻辑。这个参数的作用仅为控制是否将CDI的EL解析器加入JSF解析链,不会影响Mojarra 2.3启动时默认执行的CDI BeanManager探测流程。Tomcat作为轻量级Servlet容器本身没有内置CDI实现,探测不到BeanManager时就会直接抛出上述FacesException,和是否开启解析器链没有关系。
按以下配置调整即可彻底关闭CDI集成,完全保留原JSF托管Bean的运行逻辑,不需要改动现有业务代码:
- 在
web.xml中补充核心CDI禁用参数,这是之前缺失的关键配置:
<context-param> <param-name>javax.faces.DISABLE_CDI</param-name> <param-value>true</param-value> </context-param>
该参数优先级最高,设置为true后JSF会直接跳过所有CDI相关的探测、集成、注解扫描逻辑,不会再尝试查找BeanManager,是JSF 2.3专门为不需要CDI的兼容场景预留的开关。
- 修改
faces-config.xml根节点,添加metadata-complete="true"属性,关闭JSF的类路径注解扫描,强制JSF完全按照XML配置加载托管Bean,和JSF 1.1的行为保持一致,参考配置:
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd" version="2.3" metadata-complete="true"> <!-- 原有managed-bean、导航规则等配置全部保留,不需要修改 --> </faces-config>
检查项目依赖,排除所有传递引入的CDI相关包(比如weld-core、cdi-api等),避免意外触发CDI加载逻辑。
之前配置的两个上下文参数可以保留,不会产生冲突:
javax.faces.PARTIAL_STATE_SAVING=false:关闭部分状态保存,兼容JSP视图下的旧组件状态逻辑javax.faces.ENABLE_CDI_RESOLVER_CHAIN=false:在CDI全局禁用的状态下这个参数不会生效,保留也无副作用。
配置完成后重启Tomcat即可正常启动,原有XML配置的managed-bean会和JSF 1.1时期一样由JSF原生机制托管,不需要额外接入CDI容器。
内容的提问来源于stack exchange,提问作者Vicky

