Introduction
In this article, I will give an overview of the microservices patterns Event Sourcing and Command Query Responsibility Segregation (CQRS) patterns. Then I will show how to apply these concepts on a Spring Web Application using Axon Framework. You can check the final code on Github.
I recommend you to already have some basic concepts of Java and Spring Boot for better comprehension.
Event Sourcing
This pattern implies every application state change should be started by an event, which should be stored. For example, at an e-commerce site, after the user clicks a product to add to the cart, this action should send a JSON event containing the product id and quantity.
The final application state will then be defined by the sequence of previously processed events.
The main benefits of using Event Sourcing instead of maintaining only the last application state are:
Audit: you can search the stored events and verify exactly which events led to the next state.
Replay: if there's an error on event processing (ex.: database is down), you can just trigger the failed events again.
Replicate: you can publish the events on a message broker (ex.: Apache Kafka) and consume on another microservice.
CQRS
A pattern that proposes the separation of reading operations from writing or updating operations. This can be done in many ways, from just creating separate classes to using distinct databases.
The main benefit of CQRS is the logic division of code, making it clearer.
Demo Application Overview
The application will consist of a Spring Boot that simulates an e-commerce checkout platform. Through REST endpoints, you can add or edit a product containing attributes of id
, name
and quantity
.
Following CQRS concepts, there will be separate modules for command and query:
Command Side: will contain the
POST
andPUT
endpoints, that will generate its respectivecommands
, which will be translated intoevents
. The events will be stored into a MongoDb database in a raw format, while also being processed to generate the final application state and stored in a Postgres database.Query Side: will contain the
GET
endpoint to fetch the latest snapshot of our e-commerce cart.
Axon Framework gives us a simple recipe on CQRS and Event Sourcing implementation, making it easy to understand the data flow.
Dependencies
spring-boot-starter
spring-boot-starter-web
spring-boot-starter-data-mongodb
spring-boot-starter-data-jpa
axon-spring-boot-starter
axon-mongo
postgresql
We will be using version 4.1.2 of axon-spring-boot-starter
, which requires a separate Axon Server running to start our Spring Boot Application. To simplify this tutorial, we won't make use of Axon Server, so we can remove its dependency by declaring on build.gradle
file:
compile('org.axonframework:axon-spring-boot-starter:4.1.2') {
exclude group: 'org.axonframework', module: 'axon-server-connector'
}
Command module configuration
We will start by creating the Command
module. If you're using IntelliJ, you can do it by clicking File > New > Module
, select Gradle
, then Java
. In ArtfactId
type commandside
then Finish
. This step will create a folder called commandside
in the root folder of your application containing a single build.gradle
file. Check its configuration here on Github repository.
Next, you need to create the structure of a Spring Boot application inside commandside
folder by creating a path internally containing your main package src/main/java/com/example/project/command
. where it will be placed your @SpringBootApplication
annotated class and all other package related classes. Check the final result here.
Inside src/main/resources
, create an application.yml
file to place your Postgres configuration. You can follow my example here.
The most important step now is the configuration of EventStorageEngine
of Axon, which will be MongoDb in our example. To do this, create a Configuration
class like this:
@Configuration
public class AxonConfig {
// The `MongoEventStorageEngine` stores each event in a separate MongoDB document
@Bean
public EventStorageEngine storageEngine(MongoClient client) {
return MongoEventStorageEngine
.builder()
.mongoTemplate(DefaultMongoTemplate
.builder()
.mongoDatabase(client)
.build())
.build();
}
}
Query
module doesn't require any special configuration. It will be a simple Spring Boot web application that fetches view models from the Postgres database.
Run your application now to check if everything works.
Conclusion
In this first part, we've discussed the basic concepts of CQRS and structured our demo application. In the next step, we will code the Command
module.