The architecture is shown below
We would clearly explain the following and how they relate:
- Aggregate (the Command Model)
- Command Handlers
- EventSourcing Handlers
- Entity (The Query Model)
- The Queries
- The Projection, EventHandlers and QueryHandlers
A command is defined as “an expression of intent to perform an operation”. A command is a class data class in kotlin or Value class in java) with fields needed to execute the command. A command are normally intended for some aggregate. The identifier in a command is annotated with @TargetAggregateIdentifier. This indicates the particular aggregate targeted by the command.
In the case of the Giftcard, there are two commands:
IssueCommand and RedeemCommand
Events are “notifications that an event have occurred”. In the case of the Giftcard, there are two events:
IssuedEvent and RedeemedEvent
Note: each command has a corresponding event
3. Aggregate(the Command Model)
An aggregate is simply an object with states(fields) and methods to alter those states. An aggregate is annotated with @Aggregate identifier. This tells Axon that the class is an aggregate and therefore would be capable of handling commands. Also this makes the framework know that this class would publish events which would be sourced from itself.
An aggregate must have a field that represents the identifier. The aggregate is annotated with @AggregateIdentifier.
Also, an aggregate requires a NoArgConstructor.
4. Command Handlers
The command handler is a function written in the aggregate class that specifies what happens when a command is executed. A command handler is normally a void function with the name handle() except for the constructor. It takes a parameter which represents the command to be executed.
Then it is annotated with the @CommandHandler annotation.
A command may usually do some validation.
At the end, a command handler would publish an event using the AggregateLifeCycle.apply() method.
5. EventSourcing Handlers
The EventSourcing handler is a function that is called when an aggregate is sourced from its events. That means changes in the state of the aggregate occurs here. Also, the events sourcing handlers combine to build the aggregate. Therefore, the state changes is implemented in the aggregate.
the AggregateIdentifier must be set in the eventsourcing handler of the very first event that occurs in the aggregate. An eventsourcing handler is annotated with @EventSourcinHandler annotation.
Components of the command side is shown below:
6. Entity (the Query Model)
Also called Summary or View. Here we now talk about the particular object we are going to return when a query is issued. This object will be an entity and therefore the class will be annotated with @Entity annotation.
In the case of the Giftcard demo, this class is called CardSummary. So this class would have an id field such that, the object can be returned when a requested using the id. I would also have other field you will need to show.
7. The Queries
Now we need to define the queries that can be sent to the query model.
In the same way you have commands associated with the command model, you also need queries associated with the query model. In the case of the GiftCard, we have two queries:
DataQuery(offset, limit): that returns a list of CardSummaries
SizeQuery: that returns the number of items
8. The Projection, EventHandlers and QueryHandlers
This is the actual component that is responsible for handling the queries to update the query model and to return it. This class should be a component. This class would project the CardSummary
This class would make use of the repository(or entityManager).
This class would contain the EventHandlers for the following:
- IssuedEvent: Create and persist a new CardSummary
- RedeemedEvent: Find the specific CardSummary from the repository and update it’s balance
The following QueryHandlers should also be provided:
- Get a list of CardSummaries: this is a method with name handle(). use the entityManager createQuery() method to do a custom query
- Get a count of CardSummaries: same here but a different query.
Components of the query side is given below: