Java Guava EventBus延迟处理程序执行嵌套事件

Java Guava EventBus延迟处理程序执行嵌套事件,java,guava,event-bus,Java,Guava,Event Bus,我的问题与非常相似,但尽管根本问题相似,但我尝试的修复却让我蒙在鼓里 我有两个事件是背靠背发射的。第二个事件取决于所有处理程序完成后第一个事件的最终状态。只有在第一场比赛没有取消的情况下,它才会开火。问题是这两个事件都是从另一个事件的处理程序中触发的 所以,虽然我不关心谁在听第一个嵌套事件,但我确实关心他们对此有何评论。我是否已经离开了events和Guava的EventBus旨在解决的问题空间 考虑到: public void parentEventHandler(ParentEvent pa

我的问题与非常相似,但尽管根本问题相似,但我尝试的修复却让我蒙在鼓里

我有两个事件是背靠背发射的。第二个事件取决于所有处理程序完成后第一个事件的最终状态。只有在第一场比赛没有取消的情况下,它才会开火。问题是这两个事件都是从另一个事件的处理程序中触发的

所以,虽然我不关心谁在听第一个嵌套事件,但我确实关心他们对此有何评论。我是否已经离开了events和Guava的EventBus旨在解决的问题空间

考虑到:

public void parentEventHandler(ParentEvent parentEvent) {
    Object nestedEvent = createNestedEvent();
    eventBus.post(nestedEvent);

    if(nestedEvent.isCancelled()) {
        return;
    }

    Object anotherNestedEvent = createOtherNestedEvent();
    eventBus.post(anotherNestedEvent);
}
我所期望的是:

1. parentEvent is posted
2. parentEventHandler is called
3. nestedEvent is posted
4. handlers of nestedEvent are called
5. finished handling nestedEvent
6. if statement checks for cancel state of nestedEvent
7.     anotherNestedEvent is posted if nestedEvent not cancelled
8.     handlers of anotherNestedEvent are called
9.     finished handling anotherNestedEvent
10 finished handling parentEvent
正在发生的事情:

1. parentEvent is posted
2. parentEventHandler is called
3. nestedEvent is posted
4. if statement checks for cancel state of nestedEvent (defaults to false)
5.     anotherNestedEvent is posted
6. finished handing parentEvent
7. handlers of nestedEvent are called
8. nestedEvent is cancelled (too late now)
9. finished handling nestedEvent
10 handlers of anotherNestedEvent are called
11 finished handling anotherNestedEvent
在第8点。无论处理程序是否取消事件,第二个事件都已排队,因为取消检查默认为false。Guava的EventBus坚持在开始下一个事件之前完成当前处理程序的运行,我相信这有它的用处,但这不是我想要的

尝试黑客:

我注意到Guava有一个ImmediateDispatcher()的实现,它在事件进入时发布事件,这与保存事件的行为相反,直到当前事件被默认PerThreadQueuedDispatcher()的所有订阅者处理为止

但是,这些其他调度器是包私有的,EventBus上没有公共API来更改要使用的调度器。分叉Guava并将和L136处的默认调度程序更改为
dispatcher.immediate()
,在本地以另一个版本号重新安装Guava,并在我的项目中自定义构建大量不一致应用程序中观察到的事件行为根本没有改变。现在我完全迷路了

是否有一种方法可以通过Guava的EventBus实现严格的后进先出事件调度,或者是否有一种不同的范例,而不是在可以取消事件并经常嵌套在其他事件处理程序中时更有意义的事件?我不在乎有多少人和哪些订阅者收听活动,但我想知道他们对活动有什么看法(即他们是否决定是否取消活动)。应用程序完全是单线程的。

如果您使用的是“常规”
EventBus
,您可以通过创建辅助事件来实现这一点

添加接口
InternalEventCallback
和类
InternalEventCallbackHandler

interface InternalEventCallback {
    void run();
}

class InternalEventCallbackHandler {

    @Subscribe
    public void internalEventHandler(InternalEventCallback r){
        r.run();
    }
}
eventBus.register(new InternalEventCallbackHandler());
在创建
EventBus
的位置,注册
InternalEventCallbackHandler

interface InternalEventCallback {
    void run();
}

class InternalEventCallbackHandler {

    @Subscribe
    public void internalEventHandler(InternalEventCallback r){
        r.run();
    }
}
eventBus.register(new InternalEventCallbackHandler());
然后在您的
parentEventHandler
中执行以下操作:

@Subscribe
public void parentEventHandler(ParentEvent parentEvent) {
    NestedEvent nestedEvent = createNestedEvent();
    eventBus.post(nestedEvent);
    eventBus.post(new InternalEventCallback() {
        @Override
        public void run() {
            if(nestedEvent.isCancelled()) {
                return;
            }

            Object anotherNestedEvent = createOtherNestedEvent();
            eventBus.post(anotherNestedEvent);
        }
    });
}
编辑:

如果将
AsyncEventBus
与“直接执行器”一起使用,则可以获得与上述示例中相同的行为,但不需要
InternalEventCallback
InternalEventCallbackHandler

EventBus eventBus = new AsyncEventBus(MoreExecutors.newDirectExecutorService());

原来我的自定义Guava构建被主机应用程序中已绑定的较早版本的Guava覆盖(当然是这样)。我最终通过代码进行了黑客攻击(可能对版本更改不是很有弹性):

public-GuavaEventService(){
this.bus=new EventBus();
试一试{
Field dispatcherField=EventBus.class.getDeclaredField(“dispatcher”);
dispatcherField.setAccessible(true);
类dispatcherClass=dispatcherField.get(this.bus).getClass().getSuperclass();
方法immediateDispatcher=dispatcherClass.getDeclaredMethod(“立即”);
立即清除设置可访问性(true);
set(this.bus,immediateDispatcher.invoke(null));
}捕获(例外情况除外){
抛出新的IllegalStateException(“未能初始化事件服务调度程序:+ex.getMessage());
}
}
然而,艾登在编辑他的答案时提出了一个更简洁的异步事件总线替代方案:
EventBus EventBus=new AsyncEventBus(MoreExecutors.newDirectExecutorService())

很有趣!虽然这将解决我目前的问题,但它确实开始有点异味。这种方法是一种被广泛接受的处理嵌套事件的解决方案,还是我应该重新考虑在这个特定用例中使用Guava的EventBus?我同意“气味”这个说法。我不知道这个解决方案是否“被广泛接受”,因为大多数用户没有和您相同的需求。我已经用另一种解决方案更新了我的答案。编辑确实满足了我的需要。这一事实让我开始认真思考为什么我的同步黑客程序不起作用。原来我的自定义Guava构建被主机应用程序中已绑定的较早版本的Guava覆盖(当然是这样)。谢谢你的意见
MoreExecutors.newDirectExecutorService()
在调用线程上运行。所以它永远不会创建新线程。