Tomcat8.5渲染JSF2.3 f:websocket组件遇AbstractMethodError求助
<f:websocket>的AbstractMethodError问题 我来帮你排查这个问题——从错误堆栈和你的配置来看,核心是版本兼容性导致的,具体来说是OCPSoft Rewrite的旧版本不支持JSF 2.3新增的WebSocket相关方法,再加上JSF初始版本的潜在bug,一起引发了AbstractMethodError。
先梳理下你的当前配置和报错信息,再给出具体的修复步骤:
你的当前配置
Maven依赖
<dependency> <groupId>org.glassfish</groupId> <artifactId>javax.faces</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet-shaded</artifactId> <version>3.0.3.Final</version> </dependency> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>6.2</version> </dependency>
测试页面(test.xhtml)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui"> <h:head> </h:head> <h:body> <h:form> <h:outputText value="#{pisSocketView.count}" styleClass="display" /> <p:commandButton value="Click" actionListener="#{pisSocketView.increment}" /> <f:websocket channel="counter" onmessage="handleMessage" /> </h:form> <script type="text/javascript"> function handleMessage(message, channel, event) { $('.display').text(message); } </script> </h:body> </html>
错误堆栈
java.lang.AbstractMethodError at javax.faces.application.ViewHandlerWrapper.getWebsocketURL(ViewHandlerWrapper.java:328) at javax.faces.application.ViewHandlerWrapper.getWebsocketURL(ViewHandlerWrapper.java:328) at com.sun.faces.push.WebsocketChannelManager.register(WebsocketChannelManager.java:151) at com.sun.faces.push.WebsocketChannelManager.register(WebsocketChannelManager.java:142) at com.sun.faces.push.WebsocketChannelManager$Proxy$_$$_WeldClientProxy.register(Unknown Source) at com.sun.faces.renderkit.html_basic.WebsocketRenderer.encodeEnd(WebsocketRenderer.java:115) at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:949) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1912) at javax.faces.render.Renderer.encodeChildren(Renderer.java:176) at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:918) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1905) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1908) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1908) at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:491) at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:194) at org.ocpsoft.rewrite.faces.RewriteViewHandler.renderView(RewriteViewHandler.java:186) at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151) at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:151) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:126) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:223) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:671) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:205) at org.apache.catalina.c...
问题根源与修复步骤
1. 核心原因:Rewrite版本不兼容JSF 2.3
从错误堆栈里的org.ocpsoft.rewrite.faces.RewriteViewHandler可以看出,你使用的Rewrite版本太旧了——JSF 2.3新增了ViewHandler.getWebsocketURL()方法,但旧版本的Rewrite的RewriteViewHandler作为ViewHandlerWrapper的子类,没有实现这个新方法,导致调用时直接抛出AbstractMethodError。
2. 具体修复操作
(1)升级OCPSoft Rewrite到兼容版本
Rewrite从3.4.1.Final开始正式支持JSF 2.3,你需要在pom.xml中添加/更新Rewrite的依赖:
<dependency> <groupId>org.ocpsoft.rewrite</groupId> <artifactId>rewrite-servlet</artifactId> <version>3.4.1.Final</version> </dependency> <dependency> <groupId>org.ocpsoft.rewrite</groupId> <artifactId>rewrite-config-faces</artifactId> <version>3.4.1.Final</version> </dependency>
如果你的项目之前已经引入了Rewrite,直接修改版本号即可。
(2)升级JSF到稳定版
你当前用的JSF 2.3.0是第一个正式版,存在一些已知的兼容性问题,建议升级到最新的2.3.x稳定版(比如2.3.14):
<dependency> <groupId>org.glassfish</groupId> <artifactId>javax.faces</artifactId> <version>2.3.14</version> </dependency>
(3)确认CDI配置完整
JSF 2.3的WebSocket功能依赖CDI,确保你的项目WEB-INF/beans.xml存在且配置正确(CDI 2.0版本):
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="2.0" bean-discovery-mode="all"/>
这个文件是CDI启用的必要条件,缺失或配置错误会导致WebSocket无法正常工作。
(4)验证Tomcat WebSocket支持
Tomcat 8.5默认已经启用WebSocket支持,错误日志中也出现了WsFilter,这部分无需额外配置,只要确保没有在项目中禁用该Filter即可。
验证修复
完成上述修改后,重新构建并部署项目,访问test.xhtml页面:
- 页面应该能正常加载,不会再抛出
AbstractMethodError - 点击"Click"按钮后,数值应该能通过WebSocket实时更新到页面上
内容的提问来源于stack exchange,提问作者bmlikota

