3. Command Handling

A state change within an application starts with a Command. A Command is a combination of expressed intent (which describes what you want done) as well as the information required to undertake action based on that intent. A Command Handler is responsible for receiving commands of a certain type and taking action based on the information contained inside it.

The use of an explicit command dispatching mechanism has a number of advantages. First of all, there is a single object that clearly describes the intent of the client. By logging the command, you store both the intent and related data for future reference. Command handling also makes it easy to expose your command processing components to remote clients, via web services for example. Testing also becomes a lot easier, you could define test scripts by just defining the starting situation (given), command to execute (when) and expected results (then) by listing a number of events and commands. The last major advantage is that it is very easy to switch between synchronous and asynchronous command processing.

The next sections provide an overview of the tasks related to creating a Command Handling infrastructure with the Axon Framework.

3.1. Creating a Command Handler

The Command Handler is the object that receives a Command of a pre-defined type and takes action based on its contents. In Axon, a Command may be any object. There is no predefined type that needs to be implemented. The Command Handler, however, must implement the CommandHandler interface. This interface declares only a single method: Object handle(T command), where T is the type of Command this Handler can process. It is not recommended to use return values, but they are allowed. Always consider using a "fire and forget" style of command handlers, where a client does not have to wait for a response. As return value in such a case, you are recommended to use either null or Void.TYPE. The latter being the official representation of the voidkeyword.

[Note]Note

Note that Command Handlers need to be explicitly subscribed to the Command Bus for the specific types of Command they can handle. See Section 3.2, “Configuring the Command Bus”.

Annotation support

Comparable to the annotation support for Event Listeners, you can also use any POJO as command handler. The added advantage is that you can configure a single class to process several types of (related) commands. Just add the @CommandHandler annotated to your methods to turn them into a command handler. These methods may only accept a single parameter, which is the command to process. Note that for each command type, there may only be one handler! This restriction counts for all handlers registered to the same command bus.

You can use the AnnotationCommandHandlerAdapter to turn your annotated class into a CommandHandler. The adapter also needs the CommandBus instance. Use the subscribe() method on the adapter to subscribe the annotated handlers to the command bus using the correct command type.

If you use Spring, you may also define an AnnotationCommandHandlerBeanPostProcessor. This post processor detects any beans that have an @CommandHandler annotated method in them and wrap them in an AnnotationCommandHandlerAdapter automatically. They will also be automatically subscribed to the CommandBus.

[Note]Note

Note that you need to be careful when mixing manual wrapping and the use of the post processor. This might result in command handler being subscribed twice. This does not have to be a problem for most command handlers, since only a single command handler can be subscribed to a specific type of command at any one time. Their subscriptions will just overwrite each other.

3.2. Configuring the Command Bus

The Command Bus is the mechanism that dispatches commands to their respective Command Handler. Though similar to the Event Bus, there is a very clear distinction to be made between the command bus and the event bus. Where Events are published to all registered listeners, commands are sent to only one (and exactly one) command handler. If no command handler is available for a dispatched command, an exception (NoHandlerForCommandException) is thrown. Subscribing multiple command handlers to the same command type will result in subscriptions replacing each other. In that case, the last subscription wins.

Axon provides a single implementation of the Command Bus: SimpleCommandBus. You can subscribe and unsubscribe command handlers using the subscribe and unsubscribe methods, respectively. They both take two parameters: the type of command to (un)subscribe the handler to, and the handler to (un)subscribe. An unsubscription will only be done if the handler passed as the second parameter was currently assigned to handle that type of command. If another command was subscribed to that type of command, nothing happens.

3.3. Command Handler Interceptors

One of the advantages of using a command bus is the ability to undertake action based on all incoming commands, such as logging or authentication. The SimpleCommandBus provides the ability to register interceptors. These interceptors provide the ability to take action both before and after command processing.

Interceptors must implement the CommandHandlerInterceptor interface. This interface declares two methods, beforeCommandHandling() and afterCommandHandling(), that both take two parameters: a CommandContext and a CommandHandler. The first contains the actual command and provides the possiblity to add meta-data to the command. This meta-data is not forwarded to the command handler, but is intended for the command handler interceptor itself. You could, for example, store transactional information in the context if your transactional boundary is at the command handling. The second parameter, the CommandHandler is the command handler that will process or has processed the command. You could, for example, base authorization requirements on information in the command handler.

If you use annotation support, the AnnotationCommandHandlerAdapter is passed as the command handler. You may call getTarget() on it to obtain the actual annotated command handler. To obtain a reference to the method that handles the command, you can use the findCommandHandlerMethodFor(Object command) method. You could, for example, use the reference to this method to find security-related annotations and perform authorization on them.

3.3.1. Managing transactions

In some cases, it is desirable to set a transaction scope around the command handling process. For example when using synchronous event handling with event handlers that update tables in a database in combintation with the JpaEventStore. By setting the transaction scope in the command dispatching process, all changes can be performed within a single transaction. This provides full consistency guarantees.

Axon provides the SpringTransactionalInterceptor, which uses Spring's PlatformTransactionManager to manage the actual transactions. A transaction is committed when command handling is successful, or rolled back if the command handler (or one of the downstream interceptors) threw an exception.