WildFly 12.0.0.Final中JSF 2.3与f:websocket的类加载问题
看起来你是想在MongoDB插入文档时,通过EJB推送消息到JSF页面的WebSocket,但部署时遇到了PushContext的类找不到异常。这个问题我之前处理过,主要是EJB模块无法访问JSF 2.3 API以及EJB环境中获取PushContext的方式不对导致的,下面给你一步步的解决方案:
1. 先明确问题根源
javax.faces.push.PushContext是JSF 2.3新增的API类,WildFly 12虽然自带了JSF 2.3(默认是Mojarra 2.3.x版本),但EJB模块的类加载器默认不会自动关联JSF API的依赖——因为JSF通常是和Web模块绑定的,EJB容器的类加载路径里没有这个类,所以部署时反射解析EJB类就会报错。
2. 给EJB模块添加JSF API依赖
如果用Maven管理项目
在EJB模块的pom.xml里添加JSF API的依赖,注意scope设为provided(因为WildFly已经自带了,不要把它打包到EJB jar里,避免类冲突):
<dependency> <groupId>javax.faces</groupId> <artifactId>javax.faces-api</artifactId> <version>2.3</version> <scope>provided</scope> </dependency>
如果是传统非Maven项目
在EJB模块的META-INF/MANIFEST.MF里添加依赖声明,或者在EAR的META-INF/jboss-deployment-structure.xml中配置模块依赖:
<jboss-deployment-structure> <sub-deployment name="你的EJB模块名称.jar"> <dependencies> <!-- 引入WildFly自带的JSF API模块 --> <module name="javax.faces.api" slot="main"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
3. 修正EJB中获取PushContext的方式
**注意:EJB中不能用FacesContext.getCurrentInstance()来获取PushContext!**因为FacesContext是和Web请求绑定的,EJB可能在后台异步执行,此时没有活跃的Web上下文,会导致FacesContext为null,而且这本来就不是EJB环境下的正确用法。
正确的做法是用PushContextFactory来获取PushContext:
import javax.ejb.Stateless; import javax.faces.push.PushContext; import javax.faces.push.PushContextFactory; @Stateless public class FoodsCosmeticsMedService { public void onMongoDocumentInserted(String message) { // 获取PushContextFactory实例 PushContextFactory pushContextFactory = PushContextFactory.getInstance(); // 获取全局的PushContext PushContext pushContext = pushContextFactory.getPushContext(); // 如果你的WebSocket是指定了通道名(比如<f:websocket channel="dataUpdates"/>) // PushContext channelPushContext = pushContext.getChannel("dataUpdates"); // 推送消息到前端 pushContext.send(message); } }
4. 验证WildFly的JSF版本配置
确保WildFly 12确实启用了JSF 2.3,检查standalone.xml(或domain.xml)里的jsf子系统配置:
<subsystem xmlns="urn:jboss:domain:jsf:1.0"> <default-jsf-library>mojarra-2.3.4.SP01</default-jsf-library> </subsystem>
如果配置的是旧版本(比如2.2),需要调整为WildFly自带的2.3版本库(具体版本号可以看WildFly的modules目录下的javax/faces/api模块)。
5. 避免类冲突
检查EJB模块和Web模块的打包内容,确保没有把JSF API的jar包(比如javax.faces-api-2.3.jar)打包到模块里——因为WildFly已经提供了这个类,重复打包会导致类加载冲突,反而引发更多问题。
按照上面的步骤调整后,重新打包EAR部署到WildFly 12,应该就能解决PushContext的ClassNotFoundException问题了,EJB也能正常推送消息到JSF的WebSocket页面。
内容的提问来源于stack exchange,提问作者NOTiFY

