/ddd-cqrs-4-java-example

Example Java DDD/CQRS/Event Sourcing microservices with Quarkus, Spring Boot and EventStore from Greg Young.

Primary LanguageJavaApache License 2.0Apache-2.0

ddd-cqrs-4-java-example

Example Java DDD/CQRS/Event Sourcing microservices with Quarkus, Spring Boot and the EventStore from Greg Young. The code uses the lightweight ddd-4-java and cqrs-4-java libaries. No special framework is used except the well known JEE/Spring standards.

Java Development Kit 17 Apache Build Status

Background

This application shows how to implement DDD, CQRS and Event Sourcing without a DDD/CQRS framework. It uses just a few small libraries in addition to standard web application frameworks like Quarkus and Spring Boot.

If you are new to the DDD/CQRS topic, you can use these mindmaps to find out more:

Here is an overview of how such an application looks like:

Overview

Components

  • Shared - Common code for all demo applications (commands, events, value objects and utilities).
  • Aggregates - DDD related code for all demo applications (aggregates, entities and business exceptions).
  • Quarkus - Two microservices (Command & Query) based on Quarkus.
  • Spring Boot - Two microservices (Command & Query) based on Spring Boot.

Getting started

The following instructions are tested on Linux (Ubuntu 22)

CAUTION: Building and running on Windows will require some (small) changes.

Prerequisites

Make sure you have the following tools installed/configured:

Clone and install project

  1. Clone the git repository
    git clone https://github.com/fuinorg/ddd-cqrs-4-java-example.git
    
  2. Change into the project's directory and run a Maven build
    cd ddd-cqrs-4-java-example
    ./mvnw install
    
    Be patient - This may take a while (~5 minutes) as all dependencies and some Docker images must be downloaded and also some integration tests will be executed.

Start Event Store and Maria DB (Console window 1)

Change into the project's directory and run Docker Compose

cd ddd-cqrs-4-java-example
docker-compose up

Start command / query implementations

Start one query service and then one command service. You can mix Quarkus & Spring Boot if you want to!

Quarkus Microservices

Quarkus Query Service (Console window 2)
  1. Start the Quarkus query service:
    cd ddd-cqrs-4-java-example/quarkus/query
    ./mvnw quarkus:dev
    
  2. Opening http://localhost:8080/ should show the query welcome page

For more details see quarkus/query.

Quarkus Command Service (Console window 3)
  1. Start the Quarkus command service:
    cd ddd-cqrs-4-java-example/quarkus/command
    ./mvnw quarkus:dev
    
  2. Opening http://localhost:8081/ should show the command welcome page

For more details see quarkus/command.

Spring Boot Microservices

Spring Boot Query Service (Console window 2)
  1. Start the Spring Boot query service:
    cd ddd-cqrs-4-java-example/spring-boot/query
    ./mvnw spring-boot:run
    
  2. Opening http://localhost:8080/ should show the query welcome page

For more details see spring-boot/query.

Spring Boot Command Service (Console window 3)
  1. Start the Spring Boot command service:
    cd ddd-cqrs-4-java-example/spring-boot/command
    ./mvnw spring-boot:run
    
  2. Opening http://localhost:8081/ should show the command welcome page

For more details see spring-boot/command.

Verify projection and query data

  1. Open http://localhost:2113/ to access the event store UI (User: admin / Password: changeit) You should see a projection named "qry-person-stream" when you click on "Projections" in the top menu.
  2. Opening http://localhost:8080/persons should show an empty JSON array

Execute some create commands (Console window 4)

Change into the demo directory and execute the command using cURL (See shell script and JSON files with commands in demo)

cd ddd-cqrs-4-java-example/demo
./create-persons.sh

Command service (Console window 3) should show something like

Update aggregate: id=PERSON 954177c4-aeb7-4d1e-b6d7-3e02fe9432cb, version=-1, nextVersion=0
Update aggregate: id=PERSON 568df38c-fdc3-4f60-81aa-d3cce9ebfd7b, version=-1, nextVersion=0
Update aggregate: id=PERSON 84565d62-115e-4502-b7c9-38ad69c64b05, version=-1, nextVersion=0

Query service (Console window 2) should show something like

Handle PersonCreatedEvent: Person 'Harry Osborn' (954177c4-aeb7-4d1e-b6d7-3e02fe9432cb) was created
Handle PersonCreatedEvent: Person 'Mary Jane Watson' (568df38c-fdc3-4f60-81aa-d3cce9ebfd7b) was created
Handle PersonCreatedEvent: Person 'Peter Parker' (84565d62-115e-4502-b7c9-38ad69c64b05) was created

Verify the query data was updated

  1. Refreshing http://localhost:8080/persons should show
    [
       {
           "id": "568df38c-fdc3-4f60-81aa-d3cce9ebfd7b",
           "name": "Mary Jane Watson"
       },
       {
           "id": "84565d62-115e-4502-b7c9-38ad69c64b05",
           "name": "Peter Parker"
       },
       {
           "id": "954177c4-aeb7-4d1e-b6d7-3e02fe9432cb",
           "name": "Harry Osborn"
       }
    ]
  2. Opening http://localhost:8080/persons/84565d62-115e-4502-b7c9-38ad69c64b05 should show
    {"id":"84565d62-115e-4502-b7c9-38ad69c64b05","name":"Peter Parker"}
  3. The event sourced data of the person aggregate could be found in a stream named PERSON-84565d62-115e-4502-b7c9-38ad69c64b05

Execute a delete command (Console window 4)

Change into the demo directory and execute the command using cURL (See shell script and JSON files with commands in demo)

cd ddd-cqrs-4-java-example/demo
./delete-harry-osborn.sh

Verify the query data was updated

  1. Refreshing http://localhost:8080/persons should show
    [
       {
           "id": "568df38c-fdc3-4f60-81aa-d3cce9ebfd7b",
           "name": "Mary Jane Watson"
       },
       {
           "id": "84565d62-115e-4502-b7c9-38ad69c64b05",
           "name": "Peter Parker"
       }
    ]
    "Harry Osborn" should no longer be present in the list.

Stop Event Store and Maria DB and clean up

  1. Stop Docker Compose (Ubuntu shortcut = ctrl c)
  2. Remove Docker Compose container
    docker-compose rm