程序员

AxonFramework命令总线

2017-06-17  本文已影响287人  勇赴

命令总线是将命令分发给各自的命令Handler的机制。每个命令总是被精确发送到一个命令Handler。如果没有可用的命令Handler为已分发的命令,将会抛出NoHandlerForCommandException异常。对同一命令类型订阅多个命令Handler将导致订阅互相取代。在这种情况下,最后一个订阅获胜。

分发命令

CommandBus提供了两个方法去分发命令到它们各自的Handler:dispatch(commandMessage,callback)和dispatch(commandMessage)。第一个参数是一个包含要发送的实际命令的消息。第二个可选的参数接收一个回调,允许在命令处理完成时通知分发组件。这个回调有两个方法:onSuccess()和onFailure(),分别会在命令处理返回后被调用,或者当它抛出一个异常时调用。

调用组件可能不采取在分发命令的同一线程中调用回调。如果调用线程在继续之前依赖于结果,你可以使用FutureCallback。这是一个Future(在java.concurrent包中定义)和Axon的CommandCallback的组合。或者,考虑使用命令网关。

如果一个应用程序不直接对命令的结果感兴趣,可以使用dispatch(commandMessage) 方法。

SimpleCommandBus

SimpleCommandBus,顾名思义,最简单的实现。它在分发它们的线程中简单的处理命令。命令处理后,修改后的聚合在同一线程被保存和发布生成的事件。在大多数情况下,如web应用程序,该实现将符合你的需求。配置API中SimpleCommandBus是默认使用的实现。

像大多数CommandBus实现一样,SimpleCommandBus允许拦截器进行配置。在命令总线上分发一个命令后调用CommandDispatchInterceptors。在实际的命令handler 方法之前调用CommandHandlerInterceptors,允许你修改或阻塞命令。有关更多信息,请参考命令处理器拦截器。

因为所有命令处理都在同一线程中完成,这个实现仅限于JVM的边界。这个实现的性能是很好的,但不超凡。跨JVM边界,或使你的CPU cycles发挥最大的功效,看看其他CommandBus实现。

AsynchronousCommandBus

顾名思义,AsynchronousCommandBus实现从分发它们的线程异步执行命令。它使用一个Executor在不同的线程来执行实际的处理逻辑。

默认情况下,AsynchronousCommandBus使用一个unbounded缓存的线程池。这意味着分发一个命令时会创建线程。完成处理命令的线程将被重新用于新命令。如果60秒线程没有处理命令,则会停止线程。

或者,Executor实例可以提供不同的线程策略配置。

注意,应用程序停止时应该关闭AsynchronousCommandBus,以确保任何等待线程正确关闭。关闭,调用shutdown()方法。这也将关闭任何Executor实例,如果它实现ExecutorService接口的话。

DisruptorCommandBus

SimpleCommandBus具有合理的性能特性,特别是当你经历了性能调优技巧。事实上,SimpleCommandBus需要锁来防止多个线程并发访问同一聚合,导致处理开销和锁争用。

DisruptorCommandBus采用不同的方法进行多线程处理。不是多个线程每个都执行同样的处理,而是有多个线程,每个负责一件处理。DisruptorCommandBus使用Disruptor,一个小的并发编程框架,通过不同的方法对多线程进行处理来实现更好的性能。任务不是在调用线程中进行处理,而是将任务移交给两组线程进行处理,每组线程负责一部分处理。第一组的线程将执行命令handler,更改一个聚合的状态。第二组将存储并将事件发布到事件存储。

虽然DisruptorCommandBus轻易优于SimpleCommandBus 4倍(!),但有一些限制:

构建一个DisruptorCommandBus实例,你需要一个EventStore。该组件在Repositories and Event Stores中有解释。
或者,你可以提供一个DisruptorConfiguration实例,它允许你调整配置优化你的特定环境下的性能:

上一篇下一篇

猜你喜欢

热点阅读