2. Architecture Overview

CQRS on itself is a very simple pattern. It only describes that the component of an application that processes commands should be separated from the component that processes queries. Although this separation is very simple on itself, it provides a number of very powerful features when combined with other patterns. Axon provides the building block that make it easier to implement the different patterns that can be used in combination with CQRS.

The diagram below shows an example of an extended layout of a CQRS architecture. The UI component, displayed on the left, interacts with the rest of the application in two ways: it sends commands to the application (shown in the top section), and it queries the application for information (shown in the bottom section).

Architecture overview of a CQRS application

Figure 2.1. Architecture overview of a CQRS application


Command Handling

Commands are represented by simple and straightforward objects that contain all data necessary for a command handler to execute it. Typically, a command expresses some intent by its name. In Java terms, that means the class name is used to figure out what needs to be done, and the fields of the command provide the information required to do it.

The Command Bus receives commands and routes them to the Command Handlers. Each command handler responds to a specific type of command and execute logic based on their contents. In some cases, however, you would also want to do things regardless of the actual type of command, such as logging or authorization.

Axon provides building blocks to help you implement a command handling infrastructure with these features. These buidling block are thorougly described in Chapter 3, Command Handling.

Domain Modeling

The command handler retrieves domain objects (Aggregates) from a repository and executes methods on them to change their state. These aggregates typically contain the actual business logic and are therefore responsible for guarding their own invariants. The state changes of aggregates result in the generation of Domain Events. Both the Domain Events and the Aggregates form the domain model. Axon provides supporting classes to help you build a domain model. They are described in Chapter 4, Domain Modeling.

Repositories and Event Stores

Once the command execution is complete, the command handler saves the aggregate's state by handing it over to the repository. The repository does two things when it saves an aggregate. It persists the aggregate's state for future commands that need to execute on this aggregate. Furthermore, events are handed over to the event bus, which is reposonsible for dispatching them to all interested listeners.

Axon provides support for both the direct way of persisting aggregates (using object-relational-mapping, for example) and for event sourcing. More about repositories and event stores can be found in Chapter 5, Repositories and Event Stores.

Event Processing

The event bus dispatches events to all interested event listeners. This can either be done synchronously or asynchronously. Asynchronous event dispatching allows the command execution to return and hand over control to the user, while the events are being dispatched and processed in the background. Not having to wait for event processing to complete makes an application more responsive. Synchronous event processing, on the other hand, is simpler and is a sensible default. Synchronous processing also allows several event listeners to process events within the same transaction.

Event listeners receive events and handle them. Some handlers might issue commands to update other aggregates, based on information in the event. An example of this is the placement of an order in an online store. When an order comes in, you might want to update stock information for all ordered items. The listener would listen to events regarding placed orders and send stock update commands to the inventory. Other event listeners will update data sources used for querying or send messages to external systems.

As you might notice, the command handlers are completely unaware of the components that are interested in the changes they make. This means that it is very non-intrusive to extend the application with new functionality. All you need to do is add another event listener. The events loosely couple all components in your application together.

The building blocks related to event handling and dispatching are explained in Chapter 6, Event Processing.

Querying for data

Some event handlers will update data in data sources, such as tables in a database. The thin data layer in between the user interface and the data sources provides a clearly defined interface to the actual query implementation used. This data layer typically returns read-only DTO objects containing query results.

Axon does not provide any building blocks for this part of the application. The main reason is that this is very straightforward and doesn't differ from the layered architecture.