CDI 2.0:在同一个观察者实例中观察多个事件
CDI 2.0: Observing multiple events in one and the same observer instance
我有两个 classes 触发两个事件(代码来自带有私有内部 classes 的 junit 测试):
private static class EventEmitter1 { @Inject private Event<EventData1> event; }
private static class EventEmitter2 { @Inject private Event<EventData2> event; }
在我的测试中 EventData classes 是微不足道的:
private class EventData1 { }
private class EventData2 { }
在接收器中class我想等到两个事件都被接收到,所以我尝试了这样的事情:
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);
}
}
在我的测试方法中,我手动 select 两个发射器 classes 的实例,并为每个实例触发一个事件。此外,我手动 select 一个 Receiver 实例。
@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);
}
手动 selection 通过 CDI.current.select(...) 应确保 CDI 机制正常工作。
我现在的问题是这边三! EventReceiver 实例被初始化。 None 其中的 eventDataXReceived 字段都设置为 true。将事件传递到同一个 EventReceiver 实例的正确方法是什么?理想情况下,EventReceiver 不应是(应用程序范围的)单例。
感谢您的帮助。
给 EventReceiver 一个适当的范围。没有范围它是@Dependend,所以对于每个事件都会创建一个新实例。
@ApplicationScoped 应该可以正常工作。
恐怕您需要为 EventReceiver
添加一个范围,@ApplicationScoped
通常是这里的首选。
您可以添加第二层逻辑,这将帮助您确定此事件从何而来,从而确定您是否已经注册了两个所需的事件(我想这就是您所追求的)。
一种可能的方法是将此类信息存储在事件负载中。然后,一旦您观察到该事件,就提取此信息并保留已注册事件的集合。添加到此集合中后,您可能会检查是否已经有给定 'type'.
的两个事件
我希望你能理解基本的想法,更准确地说,我需要更多地了解代码。
最后但同样重要的是,define your own scope 还有一个(疯狂的)选项,您可以根据自己的需要进行调整。然而,这需要认真的投入和努力。
这是一个适合我的解决方案:
- 创建一个抽象事件调度程序类型,它观察您感兴趣的通用事件类型 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.
感兴趣的消费者
- 为自定义事件 E(下例中的
Event
)创建一个非抽象的 EventDispatcher,并为其指定一个作用域(下例中的Singleton
):
@Singleton private static class Dispatcher extends EventDispatcher<Event> { }
注意:private static
类型完全足以完成它的小任务。
- 在您的 CDI 应用程序的任何位置使用 (
@Inject
) 您的 Dispatcher
:
@Inject private Dispatcher dispatcher;
- 将消费者添加到您的
dispatcher
并在 Event
发生时做您认为合适的事情,例如onEvent(event)
:
dispatcher.getConsumers().add(event -> onEvent(event));
我有两个 classes 触发两个事件(代码来自带有私有内部 classes 的 junit 测试):
private static class EventEmitter1 { @Inject private Event<EventData1> event; }
private static class EventEmitter2 { @Inject private Event<EventData2> event; }
在我的测试中 EventData classes 是微不足道的:
private class EventData1 { }
private class EventData2 { }
在接收器中class我想等到两个事件都被接收到,所以我尝试了这样的事情:
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);
}
}
在我的测试方法中,我手动 select 两个发射器 classes 的实例,并为每个实例触发一个事件。此外,我手动 select 一个 Receiver 实例。
@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);
}
手动 selection 通过 CDI.current.select(...) 应确保 CDI 机制正常工作。
我现在的问题是这边三! EventReceiver 实例被初始化。 None 其中的 eventDataXReceived 字段都设置为 true。将事件传递到同一个 EventReceiver 实例的正确方法是什么?理想情况下,EventReceiver 不应是(应用程序范围的)单例。
感谢您的帮助。
给 EventReceiver 一个适当的范围。没有范围它是@Dependend,所以对于每个事件都会创建一个新实例。
@ApplicationScoped 应该可以正常工作。
恐怕您需要为 EventReceiver
添加一个范围,@ApplicationScoped
通常是这里的首选。
您可以添加第二层逻辑,这将帮助您确定此事件从何而来,从而确定您是否已经注册了两个所需的事件(我想这就是您所追求的)。
一种可能的方法是将此类信息存储在事件负载中。然后,一旦您观察到该事件,就提取此信息并保留已注册事件的集合。添加到此集合中后,您可能会检查是否已经有给定 'type'.
的两个事件我希望你能理解基本的想法,更准确地说,我需要更多地了解代码。
最后但同样重要的是,define your own scope 还有一个(疯狂的)选项,您可以根据自己的需要进行调整。然而,这需要认真的投入和努力。
这是一个适合我的解决方案:
- 创建一个抽象事件调度程序类型,它观察您感兴趣的通用事件类型 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.
- 为自定义事件 E(下例中的
Event
)创建一个非抽象的 EventDispatcher,并为其指定一个作用域(下例中的Singleton
):
@Singleton private static class Dispatcher extends EventDispatcher<Event> { }
注意:private static
类型完全足以完成它的小任务。
- 在您的 CDI 应用程序的任何位置使用 (
@Inject
) 您的Dispatcher
:
@Inject private Dispatcher dispatcher;
- 将消费者添加到您的
dispatcher
并在Event
发生时做您认为合适的事情,例如onEvent(event)
:
dispatcher.getConsumers().add(event -> onEvent(event));