在我的设置中,我稍微自定义了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秒钟后发布新消息。
有什么方法可以创建一种架构测试来检查此类事件循环吗?