在与托管bean分开运行的线程中访问OmniFaces PushContext实例

时间:2016-12-15 19:35:41

标签: multithreading jsf websocket cdi omnifaces

我在访问PushContext实例时遇到了一些问题。

我想将消息发送到与托管bean分开运行的线程中。通过@Injected @Push注入,我不能。有谁知道我怎么能这样做?

1 个答案:

答案 0 :(得分:1)

  

在线程中访问OmniFaces PushContext实例

PushContext只能注入驻留在WAR中的容器管理工件(例如@Named@WebServlet@WebFilter@WebListener等) ,而不是其他地方(即绝对不在@Stateless@Stateful@Singleton等。)

  

我想在与托管bean分开运行的线程中发送消息

只有当线程由容器管理时才会起作用,例如由EJB @Asynchronous启动的线程。如果线程不受管理(即使用Thread手动创建),它将无法工作。这在Is it safe to start a new thread in a JSF managed bean?

中有详细解释

正确使用EJB的@Asynchronous时,只需按照<o:socket>文档中的示例操作即可。您可以在EJB design hints部分找到它们。

documentation的以下摘录显示了如何通过@Asynchronous EJB方法推送应用程序范围的套接字,而后者又被某个后台作业调用(例如{{ 1}})。

  

如果您想从EAR / EJB端触发推送到应用程序范围的推送套接字,那么您可以使用CDI事件。首先创建一个表示push事件的自定义bean类,类似于下面的PushEvent,将你想要的任何内容作为推送消息传递。

@Schedule
     

然后使用public final class PushEvent { private final String message; public PushEvent(String message) { this.message = message; } public String getMessage() { return message; } } 来发起CDI事件。

BeanManager.fireEvent(Object, java.lang.annotation.Annotation...)
     

最后,只需@Observes它在WAR中的某个请求或应用程序范围的CDI托管bean中,并委托给PushContext,如下所示。

@Inject
private BeanManager beanManager;

public void onSomeEntityChange(Entity entity) {
    beanManager.fireEvent(new PushEvent(entity.getSomeProperty()));
}

documentation的以下摘录显示了如何通过@Inject @Push private PushContext someChannel; public void onPushEvent(@Observes PushEvent event) { someChannel.send(event.getMessage()); } EJB方法推送到会话视图范围的套接字由某些JSF动作调用。

  

如果EAR / EJB端的触发器是在WAR端启动的异步服务方法,那么您可以使用WAR端的回调。让业务服务方法将回调实例作为参数,例如@Asynchronous功能界面。

java.util.function.Consumer
     

并在WAR中调用异步服务方法,如下所示。

@Asynchronous
public void someAsyncServiceMethod(Entity entity, Consumer<Object> callback) {
    // ... (some long process)
    callback.accept(entity.getSomeProperty());
}