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

时间:2016-07-03 21:28:48

标签: java events cdi observers

我有两个类可以触发两个事件(代码来自带有私有内部类的junit测试):

55|32|11

在我的测试中,EventData类很简单:

private static class EventEmitter1 { @Inject private Event<EventData1> event; }
private static class EventEmitter2 { @Inject private Event<EventData2> event; }

在接收器类中,我想等到收到两个事件,所以我尝试了这样的事情:

private class EventData1 { }
private class EventData2 { }

在我的测试方法中,我手动为两个发射器类选择一个实例,并为每个实例触发一个事件。此外,我手动选择一个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); 
    }
}

通过CDI.current.select(...)手动选择应确保CDI机制有效。

我现在的问题是这三种方式! EventReceiver实例初始化。他们都没有将eventDataXReceived字段都设置为true。将事件传递到同一个EventReceiver实例的正确方法是什么?理想情况下,EventReceiver不应该是(应用程序作用域)单例。

Thanx求助。

3 个答案:

答案 0 :(得分:1)

这是一个对我有用的解决方案:

  1. 创建一个抽象的事件调度程序类型,用于观察您感兴趣的通用事件类型 E。通用方法可能如下所示:
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));
    }
}

注意:EventDispatcher 提供 getConsumers() 允许注册对 E 感兴趣的消费者。

  1. 为自定义事件 E(以下示例中的 Event)创建一个非抽象 EventDispatcher 并为其指定范围(以下示例中的 Singleton):
    @Singleton private static class Dispatcher extends EventDispatcher<Event> { }

注意:private static 类型完全满足它的小任务。

  1. 在 CDI 应用程序的任何位置使用 (@Inject) 您的 Dispatcher
    @Inject private Dispatcher dispatcher;
  1. 将消费者添加到您的 dispatcher 并在 Event 出现时执行您认为合适的操作,例如onEvent(event)
        dispatcher.getConsumers().add(event -> onEvent(event));

答案 1 :(得分:0)

为EventReceiver提供适当的范围。如果没有范围,则为@Dependend,因此对于每个事件都会创建一个新实例。

@ApplicationScoped应该可以正常工作。

答案 2 :(得分:0)

我担心你需要为EventReceiver添加一个范围,而@ApplicationScoped通常会成为这里的首选。

你可以添加一个辅助逻辑层来帮助你确定这个事件的来源,从而确定你是否已经注册了所有必需的事件(我想这就是你所追求的)。

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

我希望你能得到基本的想法,更确切地说,我需要了解更多关于代码的知识。

最后但同样重要的是,define your own scope还有一个(疯狂)选项,您可以根据自己的需要进行定制。然而,这需要一些认真的奉献和工作。