Java CDI 2.0:在同一个观察者实例中观察多个事件

Java CDI 2.0:在同一个观察者实例中观察多个事件,java,events,cdi,observers,Java,Events,Cdi,Observers,我有两个类触发两个事件代码来自junit测试和私有内部类: private static class EventEmitter1 { @Inject private Event<EventData1> event; } private static class EventEmitter2 { @Inject private Event<EventData2> event; } 在receiver类中,我希望等待两个事件都被接收,因此我尝试了以下方法: private s

我有两个类触发两个事件代码来自junit测试和私有内部类:

private static class EventEmitter1 { @Inject private Event<EventData1> event; }
private static class EventEmitter2 { @Inject private Event<EventData2> event; }
在receiver类中,我希望等待两个事件都被接收,因此我尝试了以下方法:

private static class EventReceiver {
    private boolean eventData1Received = false;
    private boolean eventData2Received = false;

    private void receiveEventData1(@Observes EventData1 eventData) {
        LOGGER.debug("received " + eventData.getClass().getName());
        eventData1Received = true;
        handleReceivedEvents();
    }

    private void receiveEventData2(@Observes EventData2 eventData) {
        LOGGER.debug("received " + eventData.getClass().getName());
        eventData2Received = true;
        handleReceivedEvents();
    }

    private void handleReceivedEvents() {
        LOGGER.debug("eventData1Received: " + eventData1Received + ", eventData2Received: " + eventData2Received); 
    }
}
在我的测试方法中,我手动为两个发射器类选择一个实例,并为每个实例触发一个事件。此外,我手动选择了一个接收器实例

@Test public void receiveEvents() {
    EventReceiver eventReceiver = CDI.current().select(EventReceiver.class).get();

    Instance<EventEmitter1> instanceEventEmitter1 = CDI.current().select(EventEmitter1.class);
    EventEmitter1 eventEmitter1 = instanceEventEmitter1.get();
    EventData1 eventData1 = new EventData1();
    eventEmitter1.event.fire(eventData1);

    Instance<EventEmitter2> instanceEventEmitter2 = CDI.current().select(EventEmitter2.class);
    EventEmitter2 eventEmitter2 = instanceEventEmitter2.get();
    EventData2 eventData2 = new EventData2();
    eventEmitter2.event.fire(eventData2);
}
通过CDI手动选择。当前。选择。。。应该确保CDI机制工作正常

我现在的问题是这条路有三条!EventReceiver实例得到初始化。它们中没有一个同时将eventDataXReceived字段设置为true。将事件传递到同一个EventReceiver实例的正确方法是什么?理想情况下,EventReceiver不应该是应用程序范围的单例


感谢您的帮助。

为EventReceiver提供适当的范围。没有作用域,它是@dependent的,因此每个事件都会创建一个新实例


@ApplicationScoped应该可以正常工作。

恐怕您需要在EventReceiver中添加一个作用域,@ApplicationScoped通常是此处的首选

您可以添加第二层逻辑,这将帮助您确定此事件来自何处,从而可以确定您是否已经注册了这两个所需的事件我想这就是您所追求的

一种可能的方法是将此类信息存储在事件负载中。然后,观察事件后,提取此信息并保留已注册事件的集合。添加到此集合中后,您可以检查是否已经有两个给定“类型”的事件

我希望您了解基本的想法,更准确地说,我需要更多地了解代码


最后但并非最不重要的一点是,还有一个疯狂的选择,您可以根据自己的需要进行定制。然而,这需要一些认真的投入和努力。

这里有一个适合我的解决方案:

创建一个抽象事件调度程序类型,该类型观察您感兴趣的通用事件类型E。通用方法可以如下所示: 注意:私有静态类型完全满足它的小任务

在CDI应用程序中的任意位置使用@Inject您的调度程序: 将使用者添加到调度程序中,并在事件发生时执行您认为合适的操作,例如onEventevent:
谢谢你的及时答复。是的,@ApplicationScoped可以做到这一点,但我不希望EventReceiver成为一个单身汉。我编辑了这个问题,因为我在原来的帖子里没有说清楚。是否有另一种方法将多个事件传递到单个接收器实例?目标环境是JSE,而不是JEE。这种方法有一些变体,比如将事件转发给单例,或者使用静态字段,或者使用非单例的自定义范围。但基本上都是一样的。@ApplicationScope有什么问题?你想解决什么问题?转发事件听起来很有趣,我很快就会尝试。我想以松散耦合的方式绑定UI组件属性JavaFX。控制器等待组件可用,然后绑定组件属性。在我的情况下,组件可能可用,也可能不可用…我不理解您对使用app scope的担忧。Afaik app scope使带注释的类型成为单例。在我的例子中,我希望在多个地方使用UI组件。设想一个TableView,它在左侧显示表a,在表a旁边显示表B,依此类推。对于每个TableView,我需要一个单独的TableViewController,所以TableViewController不应该是单例的。
@Test public void receiveEvents() {
    EventReceiver eventReceiver = CDI.current().select(EventReceiver.class).get();

    Instance<EventEmitter1> instanceEventEmitter1 = CDI.current().select(EventEmitter1.class);
    EventEmitter1 eventEmitter1 = instanceEventEmitter1.get();
    EventData1 eventData1 = new EventData1();
    eventEmitter1.event.fire(eventData1);

    Instance<EventEmitter2> instanceEventEmitter2 = CDI.current().select(EventEmitter2.class);
    EventEmitter2 eventEmitter2 = instanceEventEmitter2.get();
    EventData2 eventData2 = new EventData2();
    eventEmitter2.event.fire(eventData2);
}
public abstract class EventDispatcher<E>
{
    private Set<Consumer<E>> consumers = new HashSet<>();

    public Set<Consumer<E>> getConsumers() { return consumers; }

    protected void observe(@Observes E event)
    {
        consumers.forEach(consumer -> consumer.accept(event));
    }
}
    @Singleton private static class Dispatcher extends EventDispatcher<Event> { }

    @Inject private Dispatcher dispatcher;
        dispatcher.getConsumers().add(event -> onEvent(event));