当前位置: 首页 > 知识库问答 >
问题:

触发CDI事件,但不是所有线程/会话都接收到

毛宏达
2023-03-14

我有一个简单的设置,只有一个会话,支持一个JSF xhtml文件。在此范围内,我触发一个事件,期望同一会话和任何其他会话在提交时都将接收该事件。

然而,奇怪的是,我可以看到在事件触发期间,只有当前会话接收到它,而没有任何其他会话。我通过使用两种不同的浏览器(本例中为Safari和Firefox)来确保我有两个不同的会话。

我是否错误地理解了基于CDI的事件的概念?

支持会话的bean:

package testevent;

import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

@Named
@SessionScoped
public class TestEventSession implements Serializable {
  private String message = "Start Message";
  private String receivedMessage = "";
  
  @Inject
  @ForTest Event<String> messageEvent;
  
  Logger LOG = LogManager.getLogger();
  
  public void messageChanged(@Observes(notifyObserver = Reception.IF_EXISTS) @ForTest String message) {
    LOG.info("messageChanged <-- "+message);
    this.receivedMessage = message;
  }

  public String getReceivedMessage() {
    return receivedMessage;
  }
  
  public String getMessage() {
    LOG.info("getMessage --> "+message);
    return message;
  }

  public void setMessage(String message) {
    LOG.info("setMessage <-- "+message);
    this.message = message;
    LOG.info("Firing Message Change");
    messageEvent.fire(message);
    LOG.info("Done Firing Message Change");
  }
}

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://xmlns.jcp.org/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  >
  <f:view transient="false">
    <h:body>
      <h:form>
        <h:inputText value="#{testEventSession.message}" />
        <h:outputText value="#{testEventSession.receivedMessage}" />
        <h:commandButton value="Submit"/>
        <h:button value="Refresh" />
      </h:form>
    </h:body>
  </f:view>
</html>

使用的限定词是一个非常基本的:

package testevent;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface ForTest {
}

作为调试输出的一部分,您可以看到只有当前线程/会话中的观察者方法接收事件:

10:45:11.213 [GUEST] [http-nio-8080-exec-32] INFO  testevent.TestEventSession - Firing Message Change
10:45:11.213 [GUEST] [http-nio-8080-exec-32] INFO  testevent.TestEventSession - messageChanged <-- Start Message #3
10:45:11.213 [GUEST] [http-nio-8080-exec-32] INFO  testevent.TestEventSession - Done Firing Message Change

请注意,这已通过TomEE 7.0测试。3,它使用assumingely OpenWebBeans 1.7。3.

  • @在sessionscoped bean中观察
  • CDI事件及其传播范围
  • 是否跨会话范围的JSF支持bean观察到CDI事件
  • CDI规范

这可能是一个预期功能,但是我在CDI-Spec中找不到明确的说明。尽管提供的示例似乎只有在观察者仅在同一会话中观察激发事件时才有意义。在产生的情况下,它清楚地说明了具有作用域bean的内部工作。我认为这是一些官方规范中滞后的文档。

到目前为止,其他解决办法似乎是:

  • 手动注册和跟踪会话bean
  • 使用JMS/消息驱动bean(MDB)

共有1个答案

濮阳赞
2023-03-14

在观察者端,只有当前活动的会话才会按规范捕获它。如果要在所有会话上广播,则需要在注册表中跟踪它们。

5.5.6 CDI 2.0:

获取bean的上下文实例,该实例根据bean的上下文实例声明observer方法。

上下文实例在6.5中定义。3 as

当前范围的上下文所服务的实例。

 类似资料:
  • 我希望运行在线程中的udp服务器在每次接收到数据报时都会触发一个事件,并发送格式为json的数据。 已为此事件定义了一个侦听器,它将调用websocketendpoint方法向所有连接的客户端广播此消息: 以及实际触发事件的处理程序: 是一个简单的POJO,其中包含要广播的消息。限定符: 这些是依赖项注入的第一步,因此我不太确定应该如何从线程内触发事件,以及如何初始化对象。我发现这个页面建议使用和

  • 我有一个4个线程同时运行的代码。我想等到所有这4个线程都完成。并且只有在那之后才能继续应用程序流程。 我尝试了两种方法: ,此方法按预期工作。 之后出现的代码仅在所有线程完成后执行。 ,这种技术允许执行代码,即使不是所有线程都已完成,也会在 之后执行。 代码示例: 我的问题: 为什么 和 不要等到所有线程都完成并打印 “我们完成了!所有线程都已完成!» 在调用 ?

  • 下面是我的代码,非常感谢。

  • 我们使用Azure服务总线队列,并使用AcceptMessage会话(代码如下)接收消息。 接受消息会话成功,但当我在消息会话上调用接收时,返回null。 这种情况不会一直发生,而是在创建队列一段时间后发生。发生这种情况时,我验证了队列不是空的。当我关闭消息会话我看到我的队列缩短(在正确的消息数量!)但是我没有收到我的信息... 我使用的代码是: 更新: 我怀疑,虽然某些会话的所有消息都已过期,但

  • 我需要一起处理相同的消息集,为此,我尝试了Azure服务总线会话启用功能。为了测试这一点,我创建了一个非常简单的应用程序,一个消息在队列中成功提交,然而,当试图在“ReceiveSessionMessage”函数中接收消息时,消息会话不会返回,程序会在这一行之后退出。 我无法找出确切的根本原因,任何帮助都将不胜感激。谢谢 等待会话客户端。AcceptMessageSessionAsync();]

  • 问题内容: TL; DR我正在寻找一种让一个线程在另一个线程中引发事件的方法 编辑: 我说“立即”一词,正如一些评论家指出的那样,这是不可能的。我的意思是,如果gui线程处于空闲状态,则应该在毫秒到十亿分之一秒的范围内相当快地发生(这应该是正确的,如果我做对的话)。 案例示例: 我有一个具有Parent类的项目。该Parent类创建一个子线程“ Gui”,该子线程包含一个javafx应用程序并实现