我无法在同一个java-ee容器中使用sessioncoped bean和ejb有状态bean在用户会话之间进行通信。通过反复试验,我决定使用数据库在用户会话之间传递消息。但是现在我遇到了问题,如何通知用户会话数据库已更改 我可以在每个用户的会话上下文中启动后台轮询线程来轮询数据库以进行更改吗?如果这可行,那么避免阻塞的最佳方法是什么,但要确保轮询bean在自己用户的会话上下文中“唤醒”?
我正在使用Glassfish 3.1.2,用户会话是CDI会话编程bean,其中包含一些用于JPA数据库访问的有状态EJB。我正在使用CDI事件总线在用户会话中传递bean周围的消息。
我尝试使用Singletons在用户会话之间进行通信。但这不起作用,因为一旦源自用户1的消息传递给用户2的bean,并且那些bean触发CDI事件,CDI事件由用户1的会话上下文处理。这是有道理的,因为消息在用户1的会话中创建。
任何帮助都将不胜感激!!
答案 0 :(得分:4)
我想我必须回答我自己的问题 -
上下文不会传播到新线程或异步调用。这是CDI 1.0规范的未定义行为,因此不需要容器来跟踪创建线程的上下文。如果您创建一个线程,然后在线程唤醒后触发CDI事件,则该CDI事件将没有活动上下文,并将抛出以下错误:org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped
或特定于您的线程尝试的作用域的内容启用。 See this Glassfish ticket,这真的不是一个错误,它只是未定义的行为。
因此,当设置任何后台轮询线程以检查用户数据是否有任何更改时,当线程检测到更改时,它无法与用户的会话上下文进行通信(通过CDI事件) 。那个时候线程没有上下文。对于少数人来说,这似乎是一个悬而未决的问题:on the jboss forum和seam forum。
希望我的解决方案有所帮助。在CDI 1.1定义将会话上下文传播到线程的方法之前,您必须让用户轮询他们自己的数据,并且当他们获得新数据时,他们可以在自己的会话上下文中对其进行操作。我设置了自己的系统来使用数据库为每个用户存储一个事件队列,当他们轮询时,他们只是遍历排队的消息并将其解雇,就好像它们是在自己的会话环境中发送的CDI消息一样。
如果我错了,焊接CDI专家可以纠正我,我将不胜感激!
答案 1 :(得分:0)
我认为CDI事件总线不能用于在用户会话之间进行通信。
使用JMS消息代理解决此问题不是更好吗?您的应用程序将扩展得更好!将其作为单独的实例运行或将其嵌入应用程序服务器中。 例如,您可以使用ActiveMQ代理。
在JMS主题上发布通知消息,并使用户会话订阅它。 我还没有使用Seam 3 JMS module,但看起来它能够弥合JMS和CDI之间的差距。使用Seam JMS,您可以在每个用户会话中接收JMS消息。文档中的示例说明了如何在@SessionScoped bean的@PostConstruct中为每个用户注册JMS侦听器。