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.
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 void
keyword.
![]() | 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 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. |
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.
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.
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.