Axon 参考指南
  • 介绍
  • 架构概览
    • DDD & CQRS 概念
    • 事件溯源
    • 事件驱动的微服务
  • Axon Server
  • 发行说明
    • Axon Framework
      • Major Releases
      • Minor Releases
    • Axon Server
      • Major Releases
      • Minor Releases Standard Edition
      • Minor Releases Enterprise Edition
    • Axon Framework Extensions
      • AMQP
        • Major Releases
      • CDI
        • Major Releases
      • JGroups
        • Major Releases
      • Kafka
        • Major Releases
        • Minor Releases
      • Kotlin
        • Experimental Releases
      • Mongo
        • Major Releases
        • Minor Releases
      • Reactor
        • Major Releases
        • Minor Releases
      • Spring Cloud
        • Major Releases
        • Minor Releases
      • Tracing
        • Major Releases
        • Minor Releases
  • Getting Started
    • 快速开始
  • Axon Framework
    • 介绍
    • 消息传递概念
      • 消息剖析
      • 消息关联
      • 消息拦截
      • 支持带注解的处理程序
      • 异常处理
      • 工作单元
    • 命令
      • 建模
        • 聚合
        • 多实体聚合
        • 聚合状态存储
        • 从另一个聚合创建聚合
        • 聚合多态性
        • 解决冲突
      • 命令调度器
      • 命令处理程序
      • 基础设施
      • 配置
    • 事件
      • 事件调度器
      • 事件处理程序
      • 事件处理器
        • 订阅事件处理器
        • 流式事件处理器
      • 事件总线和事件存储
      • 事件版本控制
    • 查询
      • 查询处理
      • 查询调度器
      • 查询处理程序
      • 实现
      • 配置
    • 长时处理过程(Sagas)
      • 实现
      • 关联
      • 基础设施
    • Deadlines
      • Deadline Managers
      • Event Schedulers
    • 测试
      • 命令 / 事件
      • 长时处理过程(Sagas)
    • 序列化
    • 调整
      • 事件快照
      • 事件处理
      • 命令处理
    • 监控和指标
    • Spring Boot 集成
    • 模块
  • Axon Server
    • 介绍
    • 安装
      • 本地安装
        • Axon Server SE
        • Axon Server EE
      • Docker / K8s
        • Axon Server SE
        • Axon Server EE
    • 管理
      • 配置
        • System Properties
        • Command Line Interface
        • REST API
        • GRPC API
      • Monitoring
        • Actuator Endpoints
        • gRPC Metrics
        • Heartbeat Monitoring
      • Clusters
      • Replication Groups
      • Multi-Context
      • Tagging
      • Backup and Messaging-only Nodes
      • Backups
      • Recovery
      • Plugins
      • Error Codes
    • 安全
      • SSL
      • 访问控制
      • 访问控制 - 标准版
      • 访问控制 - 企业版
      • 访问控制 - 客户端应用程序
      • 访问控制 - 命令行
      • 访问控制 - REST API
      • 访问控制 - LDAP
      • 访问控制 - OAuth 2.0
    • 性能
      • 事件段
      • 流量控制
    • 迁移
      • Standard to Enterprise Edition
      • Non-Axon Server to Axon Server
  • Extensions
    • Spring AMQP
    • JGroups
    • Kafka
    • Kotlin
    • Mongo
    • Reactor
      • Reactor Gateways
    • Spring Cloud
    • Tracing
  • Appendices
    • A. RDBMS Tuning
    • B. Message Handler Tuning
      • 参数解析器
      • 处理程序增强
    • C. 元数据注解
    • D. 标识符生成
    • E. Axon Server Query Language
由 GitBook 提供支持
在本页
  • The Command Bus
  • The Command Gateway
  • Command Dispatching Results
  1. Axon Framework
  2. 命令

命令调度器

Command Dispatchers

上一页解决冲突下一页命令处理程序

最后更新于2年前

The pages provide the background on how to handle command messages in your application. The dispatching process is the starting point of such a command message. Axon provides two interfaces you can use to send the commands to your command handlers, being:

  1. The Command Bus, and

  2. The Command Gateway

This page will show how and when to use the command gateway and bus. How to configure and specifics on the command gateway and bus implementations are discussed in the section.

The Command Bus

The 'Command Bus' is the mechanism that dispatches commands to their respective command handlers. As such it is the infrastructure component that is aware which component can handle which command.

Each command is always sent to exactly one command handler. If no command handler is available for the dispatched command, a NoHandlerForCommandException exception is thrown.

The CommandBus provides two methods to dispatch commands to their respective handler, being the dispatch(CommandMessage) and dispatch(CommandMessage, CommandCallback) methods:

private CommandBus commandBus; // 1.

public void dispatchCommands() {
    String cardId = UUID.randomUUID().toString(); // 2.

    // 3. & 4.
    commandBus.dispatch(GenericCommandMessage.asCommandMessage(new IssueCardCommand(cardId, 100, "shopId")));

    // 5. & 6.
    commandBus.dispatch(
            GenericCommandMessage.asCommandMessage(new IssueCardCommand(cardId, 100, "shopId")),
            (CommandCallback<IssueCardCommand, String>) (cmdMsg, cmdResultMsg) -> {
                // 7.
                if (cmdResultMsg.isExceptional()) {
                    Throwable throwable = cmdResultMsg.exceptionResult();
                } else {
                    String commandResult = cmdResultMsg.getPayload();
                }
            }
    );
}
// omitted class, constructor and result usage

The CommandDispatcher described above exemplifies a couple of important aspects and capabilities of the dispatching commands:

  1. The CommandBus interface providing the functionality to dispatch command messages.

  2. The aggregate identifier is, per best practice, initialized as the String of a random unique identifier.

    Typed identifier objects are also possible, as long as the object implements a sensible toString() function.

  3. The GenericCommandMessage#asCommandMessage(Object) method is used to create a CommandMessage.

    To be able to dispatch a command on the CommandBus, you are required to wrap your own command object (e.g. the 'command message payload') in a CommandMessage.

  4. The CommandBus#dispatch(CommandMessage) function will dispatch the provided CommandMessage on the bus, for delivery to a command handler.

    If an application isn't directly interested in the outcome of a command, this method can be used.

  5. If the outcome of command handling is relevant for your application, the optional second parameter can be provided, the CommandCallback.

    The CommandCallback allows the dispatching component to be notified when command handling is completed.

  6. The Command Callback has one function, onResult(CommandMessage, CommandResultMessage), which is called when command handling has finished.

    The first parameter is the dispatched command, whilst the second is execution result of the dispatched command.

    Lastly, the CommandCallback is a 'functional interface' due to onResult being its only method.

    As such, commandBus.dispatch(commandMessage, (cmdMsg, commandResultMessage) -> { /* ... */ }) would also be possible.

  7. The CommandResultMessage provides the API to verify whether command execution was exceptional or successful.

    If CommandResultMessage#isExceptional returns true, you can assume that the CommandResultMessage#exceptionResult will return a Throwable instance containing the actual exception.

    Otherwise, the CommandResultMessage#getPayload method may provide you with an actual result or null, as further specified here.

Command Callback consideration

In the case that dispatch(CommandMessage, CommandCallback) is used, the calling component may not assume that the callback is invoked in the same thread that dispatched the command. If the calling thread depends on the result before continuing, you can use the FutureCallback. The FutureCallback is a combination of a Future (as defined in the java.concurrent package) and Axon's CommandCallback. Alternatively, consider using a CommandGateway.

The Command Gateway

The 'Command Gateway' is a convenience approach towards dispatching commands. It does so by abstracting certain aspects for you when dispatching a command on the CommandBus. It this uses the CommandBus underneath to perform the actual dispatching of the message. While you are not required to use a gateway to dispatch commands, it is generally the easiest option to do so.

The CommandGateway interface can be separated in two sets of methods, namely send and sendAndWait:

private CommandGateway commandGateway; // 1.

public void sendCommand() {
    String cardId = UUID.randomUUID().toString(); // 2.

    // 3.
    CompletableFuture<String> futureResult = commandGateway.send(new IssueCardCommand(cardId, 100, "shopId"));
}
// omitted class, constructor and result usage

The send API as shown above introduces a couple of concepts, marked with numbered comments:

  1. The CommandGateway interface providing the functionality to dispatch command messages.

  2. The aggregate identifier is, per best practice, initialized as the String of a random unique identifier.

    Typed identifier objects are also possible, as long as the object implements a sensible toString() function.

  3. The send(Object) function requires a single parameter, the command object.

    This is an asynchronous approach to dispatching commands.

    As such the response of the send method is a CompletableFuture.

Callback when using send(Object)

The CommandGateway#send(Object) method uses the FutureCallback under the hood to unblock the command dispatching thread from the command handling thread.

A synchronous approach to sending messages can also be achieved, by using the sendAndWait methods:

private CommandGateway commandGateway;

public void sendCommandAndWaitOnResult() {
    IssueCardCommand commandPayload = new IssueCardCommand(UUID.randomUUID().toString(), 100, "shopId");
    // 1.
    String result = commandGateway.sendAndWait(commandPayload);

    // 2.
    result = commandGateway.sendAndWait(commandPayload, 1000, TimeUnit.MILLISECONDS);
}
// omitted class, constructor and result usage
  1. The CommandGateway#sendAndWait(Object) function takes in a single parameter, your command object.

    It will wait indefinitely until the command dispatching and handling process has been resolved.

  2. If waiting indefinitely is not desirable, a 'timeout' paired with the 'time unit' can be provided along side the command object.

    Doing so will ensure that the command dispatching thread will not wait longer than specified.

    If command dispatching/handling was interrupted or the timeout was reached whilst using this approach, the command result will be null.

Command Dispatching Results

Dispatching commands will, generally speaking, have two possible outcomes:

  1. Command handled successfully, and

  2. command handled exceptionally

The outcome to some extent depends on the dispatching process, but more so on the implementation of the command handler. Thus if the @CommandHandler annotated function throws an exception due to some business logic, it will be that exception which will be the result of dispatching the command.

The successful resolution of command handling intentionally should not provide any return objects. Thus, if the CommandBus/CommandGateway provides a response (either directly or through the CommandResultMessage), then you should assume the result of successful command handling to return null.

The CommandMessage also allows the addition of to the Command Message.

It does so by internally leveraging the CommandBus interface .

This allows for chaining of follow up operations after the command has been returned.

The result returned by this method can either be successful or exceptional, as will be explained .

In all other scenarios, the result follows the approach.

While it is possible to return results from command handlers, this should be used sparsely. The intent of the Command should never be to retrieve a value, as that would be an indication that the message should be designed as a . Exceptions to this would be the identifier of the Aggregate Root, or identifiers of entities the Aggregate Root has instantiated. The framework has one such exception build in, on the @CommandHandler annotated constructor of an Aggregate. In case the 'command handling constructor' has executed successfully, instead of the Aggregate itself, the value of the @AggregateIdentifier annotated field will be returned.

Command Handlers
infrastructure
Query Message
Axon Coding Tutorial #5: - Connecting the UI
dispatch messages
result
here
referenced
MetaData