MDB触发CDI事件以更新JSF页面



是否可以从MDB激发CDI事件?这个MDB正在监视JMS队列,然后需要更新JSF页面。

我遇到的问题是JSFbean有一个作用域(是会话,但正在尝试请求),而MDB没有作用域。JSFbean包含控制器代码(更新页面)和方法参数上的@Observes注释。因为MDB不在"上下文"中,也没有作用域,所以CDI事件永远不会在JSF Bean上触发。

那么,如何能够基于JMS(带MDB)事件更新JSF页面呢?

免责声明,我很确定我在这里的声明,但不是100%。

您不能只使用MDB和CDI事件。通常,CDI事件重用请求线程,并在调用方法后同步执行事件。这意味着即使它有效,它也是一个潜在的瓶颈。第二部分是,它将根据产生它的请求找到观察者,而不会找到其他"用户"或其他什么。

您可以通过几种不同的方式和多种技术来实现这一点,但WebSockets/Atmosphere框架通常是一种可靠的方式来发布消息。请注意,Primefaces Push存在,并且基于大气。

我最近有一个项目(小项目),我需要一个普通的tomcat,但我不能使用WebSockets,所以我使用CDI事件制定了一个解决方案。

它是这样工作的:

  1. 我没有使用event.fire(new myEvent()),而是选择了更透明的方式(我希望它能清楚地表明这一活动将向所有会议广播)。所以我创建了我称之为SessionEventDelegator的东西。它有一个名为putEvent(Object object)的方法(当您需要限定符时,也可以使用其他方法)。当您想将事件发送到所有会话时,只需注入并"放置"您的事件。也许我应该称之为负载,因为它稍后会被解雇;p

  2. 稍后,JSF PhaseListener调用getEvents()并获取自上次检查以来的所有新事件。时间戳功能已经到位,因此您只能获得新的事件。

  3. 现在只需迭代找到的事件,并使用BeanManager.fire将它们取出。

  4. 由于PhaseListener只会在用户发出新请求时触发,所以我使用来自素数面的p:poll,确保它每三秒钟轮询一次新事件。

  5. 清理算法确保每个人获得的事件都从SessionEventDelegator中的队列中删除。

如果你想要代码,请告诉我。如果你觉得不合适,就懒得粘贴。

如果CDI事件不起作用(我不相信这一点,因为规范说非上下文对象不能观察到事件,所以没有什么可以触发它们),但最简单的解决方法似乎是使用拦截器。MDB可以有拦截器,所以只需拦截onMessage方法并从拦截器中激发事件。

是的,您可以从MDB中激发CDI事件。问题是,它们只会在应用程序级别上被观察到。如果您使用推送技术(例如Websockets),您可以让这个ApplicationScoped对象接收事件,然后根据Websockets中的会话id推送到适当的客户端。

在RichFaces库中,有一个a4j:push组件可以满足您的需要。查看RichFaces推送部分

最新更新