事件在AsyncEventbus上发布了多次

时间:2018-12-27 23:37:10

标签: java spring guava spring-aop event-bus

在我的设置中,我稍微自定义了Guava(版本24.1)AsyncEventBus

public class PausableAsyncEventBus extends AsyncEventBus implements IPausableEventBus{
    private boolean paused = false;
    private LinkedList<Object> queuedEvents = new LinkedList<>();

    public PausableAsyncEventBus(Executor executor, SubscriberExceptionHandler subscriberExceptionHandler) {
        super(executor, subscriberExceptionHandler);
    }
    public void pause() {
        paused = true;
    }
    public void resume() {
        paused = false;
        while (!paused && !queuedEvents.isEmpty()) {
            super.post(queuedEvents.removeFirst());
        }
    }

    @Override
    public void post(Object event) {
        if (!paused) {
            super.post(event);
        } else {
            queuedEvents.add(event);
        }
    }
}

然后我有一个执行一次的任务,该任务发布了一个事件。 AsyncEventBus是通过Spring依赖项注入来注入的:

@Autowired
private AsyncEventBus clientServerEventBus;

public void run() {
    log.info("Run CelebrationTask for "+ this, new Exception("Called from"));
    // calculate number of guests
    CelebrationState state = calculateCelebrationState();
    TargetedDialogStateWrapper wrapper = new TargetedDialogStateWrapper(player, state);
    clientServerEventBus.post(wrapper);
    // update reputation
    updateReputation(state);
}

我在post方法上定义了AOP方面,因此我可以记录发布的事件。这篇文章的结果如下:

2018-12-27 23:52:53,783 [pool-2-thread-4] INFO  c.s.g.o.c.l.EventBusAspect : Posted event on event bus 'PausableAsyncEventBus (default)' ch.sahits.game.openpatrician.model.ui.TargetedDialogStateWrapper 35645f14-e0d9-40f0-aa1e-e1c6f99e8d43: Thomas Pfeffersack from ch.sahits.game.openpatrician.clientserverinterface.model.task.CelebrationTask.run
2018-12-27 23:55:03,212 [pool-2-thread-3] INFO  c.s.g.o.c.l.EventBusAspect : Posted event on event bus 'PausableAsyncEventBus (default)' ch.sahits.game.openpatrician.model.ui.TargetedDialogStateWrapper 35645f14-e0d9-40f0-aa1e-e1c6f99e8d43: Thomas Pfeffersack from ch.sahits.game.openpatrician.clientserverinterface.model.task.CelebrationTask.run
2018-12-27 23:55:08,215 [pool-2-thread-3] INFO  c.s.g.o.c.l.EventBusAspect : Posted event on event bus 'PausableAsyncEventBus (default)' ch.sahits.game.openpatrician.model.ui.TargetedDialogStateWrapper 35645f14-e0d9-40f0-aa1e-e1c6f99e8d43: Thomas Pfeffersack from ch.sahits.game.openpatrician.clientserverinterface.model.task.CelebrationTask.run
2018-12-27 23:55:13,218 [pool-2-thread-3] INFO  c.s.g.o.c.l.EventBusAspect : Posted event on event bus 'PausableAsyncEventBus (default)' ch.sahits.game.openpatrician.model.ui.TargetedDialogStateWrapper 35645f14-e0d9-40f0-aa1e-e1c6f99e8d43: Thomas Pfeffersack from ch.sahits.game.openpatrician.clientserverinterface.model.task.CelebrationTask.run
2018-12-27 23:55:18,303 [pool-2-thread-3] INFO  c.s.g.o.c.l.EventBusAspect : Posted event on event bus 'PausableAsyncEventBus (default)' ch.sahits.game.openpatrician.model.ui.TargetedDialogStateWrapper 35645f14-e0d9-40f0-aa1e-e1c6f99e8d43: Thomas Pfeffersack from ch.sahits.game.openpatrician.clientserverinterface.model.task.CelebrationTask.run

run方法上的日志行仅出现一次,因此我知道run方法仅被调用一次,但是该事件在多个线程上多次发布。依次导致对同一事件的多次处理。

我这方面的基本内容如下:

@Pointcut("execution(public void com.google.common.eventbus.EventBus.post(Object))")
public void syncEventBus(){}

@Pointcut("execution(public void com.google.common.eventbus.EventBus.post(Object))")
public void asyncEventBus(){}

@Before("syncEventBus() || asyncEventBus()")
public void logEvent(JoinPoint joinPoint) {
    Object event = joinPoint.getArgs()[0];
    if (!ignore(event)) {
        String name = ((EventBus) joinPoint.getTarget()).identifier();
        StringBuilder sb = ...
        log.info(sb.toString());
    }
}

我只是看不到哪里出错了。这可能与Eventbus由Spring代理的方面有关,或者与我完全想不到的完全不同。有什么想法吗?

[编辑:] 请注意,前两个日志条目位于不同的线程上,并且相隔几分钟,所有后续日志条目与第二个日志条目位于同一线程上,相隔仅几秒钟。但是,在这些日志行之间,还存在其他已记录的事件,这些事件是为简化起见而删除的。

[EDIT2:]

我找到了原因。在@Subscribe d事件处理程序方法中,我有:

executor.schedule(() -> clientServerEventBus.post(new TargetedEvent((IHumanPlayer) player, wrappedDialogState)), 5, TimeUnit.SECONDS);

wrappedDialogState为事件对象。 然后,我有另一种方法订阅TargetedEvent

@Subscribe
public void propagate(TargetedEvent message) {
    clientServerEventBus.post(message.getEvent());
}

这当然会调用第一个事件处理程序,它将在5秒钟后发布新消息。

有什么方法可以创建一种架构测试来检查此类事件循环吗?

0 个答案:

没有答案