You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级至JSF2.3后使用<f:websocket />出现CdiUtils空指针异常求助

解决JSF 2.3 WebSocket渲染时的NullPointerException问题

嘿,看你的异常栈就能定位到问题核心了——空指针出现在WebsocketRenderer.encodeEnd调用链里的CdiUtils.getBeanReferenceByType,这说明JSF在渲染<f:websocket>组件时,根本拿不到CDI容器提供的Bean引用。结合你用的Tomcat 9 + Spring 5 + JSF 2.3组合,问题根源很明确:Tomcat本身不带完整的CDI容器,而JSF 2.3的WebSocket功能是强制依赖CDI的,再加上Spring和JSF的DI体系需要额外适配,才导致了这个报错。

下面是一步步的解决办法:

  • 第一步:给Tomcat补上CDI实现
    Tomcat默认只提供CDI的API接口,没有具体实现。你得给项目加一个CDI容器,比如Weld或者OpenWebBeans。以Weld为例,在你的pom.xml里加这个依赖:

    <dependency>
        <groupId>org.jboss.weld.servlet</groupId>
        <artifactId>weld-servlet-shaded</artifactId>
        <version>3.1.9.Final</version>
    </dependency>
    

    然后在WEB-INF目录下创建一个beans.xml文件(内容可以很简单,主要是告诉CDI容器要扫描哪些Bean):

    <?xml version="1.0" encoding="UTF-8"?>
    <beans 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/beans_2_0.xsd"
           bean-discovery-mode="all">
    </beans>
    
  • 第二步:让JSF和Spring的DI体系打通
    Spring有自己的依赖注入机制,JSF默认用CDI,得让它们俩能互相识别。你可以在faces-config.xml里配置Spring的EL解析器,让JSF用Spring的DI来获取Bean:

    <application>
        <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    </application>
    

    另外,确保你的Spring配置类里开启了组件扫描,比如加了@ComponentScan注解,相关的WebSocket后端Bean能被Spring正确注册。

  • 第三步:检查<f:websocket>的配置是否合规
    确认你在index.xhtml里的<f:websocket>标签配置没问题,比如channel属性要和后端@Push注解的通道名对应。举个例子:
    前端xhtml代码:

    <f:websocket channel="notificationChannel" onmessage="handleNotification" />
    

    后端对应的Bean要用上CDI的@Named注解(或者同时加Spring的@Component,让两边都能识别):

    @Named
    @RequestScoped
    public class NotificationPushBean {
        @Push(channel = "notificationChannel")
        private PushContext pushContext;
    
        public void sendNotification(String message) {
            pushContext.send(message);
        }
    }
    

    这里要注意,JSF的@Push注解依赖CDI,所以后端Bean必须被CDI容器管理,用@Named是最直接的方式。

  • 第四步:排查Tomcat和Spring Security的干扰
    首先确认Tomcat 9的WebSocket功能是正常开启的(默认是开的),项目里不要加冲突的WebSocket依赖。然后检查Spring Security的过滤器链,确保WebSocket的请求路径(默认是/javax.faces.push/*)没有被拦截,你可以在Spring Security配置里放行这个路径:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/javax.faces.push/**").permitAll()
            // 其他你的配置...
    }
    

如果试了上面的步骤还是不行,还有两个小技巧:

  • 把JSF版本升级到2.3.x的最新稳定版(比如2.3.14),官方在后续版本里修复了不少CDI集成的小bug
  • 检查项目里有没有其他老旧的JSF或者CDI相关依赖,比如残留的JSF 2.2的jar包,这些可能会和2.3版本冲突

内容的提问来源于stack exchange,提问作者snakedog

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:32:18