diff --git a/axon/pom.xml b/axon/pom.xml
new file mode 100644
index 0000000000..2bffa53bb8
--- /dev/null
+++ b/axon/pom.xml
@@ -0,0 +1,52 @@
+
+
+
+ parent-modules
+ com.baeldung
+ 1.0.0-SNAPSHOT
+
+ 4.0.0
+
+ axon
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+
+ org.axonframework
+ axon-test
+ ${axon.version}
+ test
+
+
+ org.axonframework
+ axon-core
+ ${axon.version}
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
+ 3.0.2
+ 4.12
+
+
+
+
\ No newline at end of file
diff --git a/axon/src/main/java/com/baeldung/axon/MessagesRunner.java b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java
new file mode 100644
index 0000000000..77b50d09bd
--- /dev/null
+++ b/axon/src/main/java/com/baeldung/axon/MessagesRunner.java
@@ -0,0 +1,54 @@
+package com.baeldung.axon;
+
+import com.baeldung.axon.aggregates.MessagesAggregate;
+import com.baeldung.axon.commands.CreateMessageCommand;
+import com.baeldung.axon.commands.MarkReadMessageCommand;
+import com.baeldung.axon.eventhandlers.MessagesEventHandler;
+import org.axonframework.commandhandling.AggregateAnnotationCommandHandler;
+import org.axonframework.commandhandling.CommandBus;
+import org.axonframework.commandhandling.SimpleCommandBus;
+import org.axonframework.commandhandling.gateway.CommandGateway;
+import org.axonframework.commandhandling.gateway.DefaultCommandGateway;
+import org.axonframework.eventhandling.AnnotationEventListenerAdapter;
+import org.axonframework.eventsourcing.EventSourcingRepository;
+import org.axonframework.eventsourcing.eventstore.EmbeddedEventStore;
+import org.axonframework.eventsourcing.eventstore.EventStore;
+import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine;
+
+import java.util.UUID;
+
+public class MessagesRunner {
+
+ public static void main(String[] args) {
+ CommandBus commandBus = new SimpleCommandBus();
+
+ CommandGateway commandGateway = new DefaultCommandGateway(commandBus);
+
+ EventStore eventStore = new EmbeddedEventStore(new InMemoryEventStorageEngine());
+
+ EventSourcingRepository repository =
+ new EventSourcingRepository<>(MessagesAggregate.class, eventStore);
+
+
+ AggregateAnnotationCommandHandler messagesAggregateAggregateAnnotationCommandHandler =
+ new AggregateAnnotationCommandHandler(MessagesAggregate.class, repository);
+ messagesAggregateAggregateAnnotationCommandHandler.subscribe(commandBus);
+
+ final AnnotationEventListenerAdapter annotationEventListenerAdapter =
+ new AnnotationEventListenerAdapter(new MessagesEventHandler());
+ eventStore.subscribe(eventMessages -> eventMessages.forEach(e -> {
+ try {
+ annotationEventListenerAdapter.handle(e);
+ } catch (Exception e1) {
+ throw new RuntimeException(e1);
+
+ }
+ }
+
+ ));
+
+ final String itemId = UUID.randomUUID().toString();
+ commandGateway.send(new CreateMessageCommand(itemId, "Hello, how is your day? :-)"));
+ commandGateway.send(new MarkReadMessageCommand(itemId));
+ }
+}
\ No newline at end of file
diff --git a/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java
new file mode 100644
index 0000000000..e762604b74
--- /dev/null
+++ b/axon/src/main/java/com/baeldung/axon/aggregates/MessagesAggregate.java
@@ -0,0 +1,36 @@
+package com.baeldung.axon.aggregates;
+
+import com.baeldung.axon.commands.CreateMessageCommand;
+import com.baeldung.axon.commands.MarkReadMessageCommand;
+import com.baeldung.axon.events.MessageCreatedEvent;
+import com.baeldung.axon.events.MessageReadEvent;
+import org.axonframework.commandhandling.CommandHandler;
+import org.axonframework.commandhandling.model.AggregateIdentifier;
+import org.axonframework.eventhandling.EventHandler;
+
+import static org.axonframework.commandhandling.model.AggregateLifecycle.apply;
+
+
+public class MessagesAggregate {
+
+ @AggregateIdentifier
+ private String id;
+
+ public MessagesAggregate() {
+ }
+
+ @CommandHandler
+ public MessagesAggregate(CreateMessageCommand command) {
+ apply(new MessageCreatedEvent(command.getId(), command.getText()));
+ }
+
+ @EventHandler
+ public void on(MessageCreatedEvent event) {
+ this.id = event.getId();
+ }
+
+ @CommandHandler
+ public void markRead(MarkReadMessageCommand command) {
+ apply(new MessageReadEvent(id));
+ }
+}
\ No newline at end of file
diff --git a/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java
new file mode 100644
index 0000000000..d0651bf12e
--- /dev/null
+++ b/axon/src/main/java/com/baeldung/axon/commands/CreateMessageCommand.java
@@ -0,0 +1,24 @@
+package com.baeldung.axon.commands;
+
+
+import org.axonframework.commandhandling.TargetAggregateIdentifier;
+
+public class CreateMessageCommand {
+
+ @TargetAggregateIdentifier
+ private final String id;
+ private final String text;
+
+ public CreateMessageCommand(String id, String text) {
+ this.id = id;
+ this.text = text;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
\ No newline at end of file
diff --git a/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java b/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java
new file mode 100644
index 0000000000..e66582d9ec
--- /dev/null
+++ b/axon/src/main/java/com/baeldung/axon/commands/MarkReadMessageCommand.java
@@ -0,0 +1,18 @@
+package com.baeldung.axon.commands;
+
+
+import org.axonframework.commandhandling.TargetAggregateIdentifier;
+
+public class MarkReadMessageCommand {
+
+ @TargetAggregateIdentifier
+ private final String id;
+
+ public MarkReadMessageCommand(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+}
\ No newline at end of file
diff --git a/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java
new file mode 100644
index 0000000000..3e51e19c4e
--- /dev/null
+++ b/axon/src/main/java/com/baeldung/axon/eventhandlers/MessagesEventHandler.java
@@ -0,0 +1,19 @@
+package com.baeldung.axon.eventhandlers;
+
+import com.baeldung.axon.events.MessageReadEvent;
+import com.baeldung.axon.events.MessageCreatedEvent;
+import org.axonframework.eventhandling.EventHandler;
+
+
+public class MessagesEventHandler {
+
+ @EventHandler
+ public void handle(MessageCreatedEvent event) {
+ System.out.println("Message received: " + event.getText() + " (" + event.getId() + ")");
+ }
+
+ @EventHandler
+ public void handle(MessageReadEvent event) {
+ System.out.println("Message read: " + event.getId());
+ }
+}
\ No newline at end of file
diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java b/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java
new file mode 100644
index 0000000000..3c9aac5ed8
--- /dev/null
+++ b/axon/src/main/java/com/baeldung/axon/events/MessageCreatedEvent.java
@@ -0,0 +1,20 @@
+package com.baeldung.axon.events;
+
+public class MessageCreatedEvent {
+
+ private final String id;
+ private final String text;
+
+ public MessageCreatedEvent(String id, String text) {
+ this.id = id;
+ this.text = text;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
\ No newline at end of file
diff --git a/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java b/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java
new file mode 100644
index 0000000000..57bfc8e19e
--- /dev/null
+++ b/axon/src/main/java/com/baeldung/axon/events/MessageReadEvent.java
@@ -0,0 +1,14 @@
+package com.baeldung.axon.events;
+
+public class MessageReadEvent {
+
+ private final String id;
+
+ public MessageReadEvent(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+}
\ No newline at end of file
diff --git a/axon/src/test/java/com/baeldung/axon/MessagesAggregateTest.java b/axon/src/test/java/com/baeldung/axon/MessagesAggregateTest.java
new file mode 100644
index 0000000000..bbeff18f27
--- /dev/null
+++ b/axon/src/test/java/com/baeldung/axon/MessagesAggregateTest.java
@@ -0,0 +1,42 @@
+package com.baeldung.axon;
+
+import com.baeldung.axon.aggregates.MessagesAggregate;
+import com.baeldung.axon.commands.CreateMessageCommand;
+import com.baeldung.axon.commands.MarkReadMessageCommand;
+import com.baeldung.axon.events.MessageCreatedEvent;
+import com.baeldung.axon.events.MessageReadEvent;
+import org.axonframework.test.aggregate.AggregateTestFixture;
+import org.axonframework.test.aggregate.FixtureConfiguration;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.UUID;
+
+public class MessagesAggregateTest {
+
+ private FixtureConfiguration fixture;
+
+ @Before
+ public void setUp() throws Exception {
+ fixture = new AggregateTestFixture(MessagesAggregate.class);
+
+ }
+
+ @Test
+ public void giveAggregateRoot_whenCreateMessageCommand_thenShouldProduceMessageCreatedEvent() throws Exception {
+ String eventText = "Hello, how is your day?";
+ String id = UUID.randomUUID().toString();
+ fixture.given()
+ .when(new CreateMessageCommand(id, eventText))
+ .expectEvents(new MessageCreatedEvent(id, eventText));
+ }
+
+ @Test
+ public void givenMessageCreatedEvent_whenReadMessageCommand_thenShouldProduceMessageReadEvent() throws Exception {
+ String id = UUID.randomUUID().toString();
+
+ fixture.given(new MessageCreatedEvent(id, "Hello :-)"))
+ .when(new MarkReadMessageCommand(id))
+ .expectEvents(new MessageReadEvent(id));
+ }
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 9243770060..ce66ff4159 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,6 +25,7 @@
aspectj
assertj
autovalue
+ axon
cdi