Saturday, July 21, 2018

How to Make Aggregates Directly Handle Commands In Axon

In 2015, I created the exploringCQRSwithAxon example project while learning about CQRS and the Axon Framework.

When I did, I set up the example project in such a way that it uses command handler classes. The setup was as follows:
  1. A controller receives a request via an endpoint
  2. Controller turns the request into a command and put it on the command gateway
  3. The command handler classes listens to specific commands. When a particular command it listens to is published via the command gateway, it loads the aggregate from the repository.
  4. The command handler class calls method on the loaded aggregate with the command that was published.
The 3rd step, most of the time, is unnecessary and can be eliminated. This is because the command handler class usually just serves as a dummy proxy that proxies commands to the aggregates.


I remember setting up the example application like this because I wanted to explore and touch as many components of the the Axon framework as possible while learning about it. I have since found out that, in practice, this particular component can be left out.

Axon makes doing away with the command handler class easy, since it provides the necessary machinery that can be used to configure the aggregates to be direct command handlers.

Updating the example project to remove the command handler classes have been on my mind for sometime but I only got around to doing so recently. The required changes was made in this commit

If you take a look at the diff, the crucial configuration changes that was required was the introduction of AggregateAnnotationCommandHandler as a bean in the configuration:

@Bean
public AggregateAnnotationCommandHandler aggregateAnnotationCommandHandler(){
   AggregateAnnotationCommandHandler<Account> handler = 
            new AggregateAnnotationCommandHandler<>(
                                          Account.class, 
                                          eventSourcingRepository());

   for (String supportedCommand : handler.supportedCommands()) {
       commandBus().subscribe(supportedCommand, handler);
   }
   return handler;
}

It is this configuration that allowed the removal of CreditAccountHandler.java and DebitAccountHandler.java and the possibility to move the @CommandHandler annotation to the Account aggregate.

As you might have also noticed, the example application still use Axon version 2.x. The next thing on my mind, which I should also find time for is to upgrade the project to use Axon 3.

One of these weekends I would get around to doing exactly that! :)


No comments: