CDI 事件已触发,但未被所有线程/会话接收

YoY*_*oYo 2 java cdi

我有一个简单的设置,只有一个会话支持 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");
  }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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

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 {
}
Run Code Online (Sandbox Code Playgroud)

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

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 {
}
Run Code Online (Sandbox Code Playgroud)

请注意,这已使用 TomEE 7.0.3 进行了测试,假设使用 OpenWebBeans 1.7.3。

有关的

更新

这可能是一个预期的功能,但是我找不到 CDI 规范中明确说明的功能。尽管提供的示例似乎仅当Observer同一会话中唯一的观察触发事件时才有意义。在这种情况下,Produces它清楚地说明了与作用域 bean 的交互。我认为这是官方规范中滞后的一些文档。

到目前为止,其他解决方案似乎是:

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

Rom*_*cau 5

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

CDI 2.0的5.5.6:

获取 Bean 的上下文实例,该实例根据 Bean 的上下文实例声明观察者方法。

上下文实例在 6.5.3 中定义为

当前作用域的上下文所服务的实例。