Bevor wir in den Axon-Pool springen, lassen Sie uns erst einmal die Grundlagen klären. Event Sourcing und CQRS sind nicht nur schicke Abkürzungen, die man bei Entwicklertreffen herumwirft (obwohl sie beeindruckend klingen). Es sind mächtige Muster, die die Art und Weise, wie wir Anwendungen entwickeln und skalieren, verändern können.
Event Sourcing: Die Zeitmaschine Ihrer Anwendung
Stellen Sie sich vor, Ihre Anwendung hätte eine eingebaute Zeitmaschine. Genau das macht Event Sourcing. Anstatt nur den aktuellen Zustand zu speichern, wird eine Aufzeichnung aller Änderungen als Ereignisse gespeichert. Es ist wie Git für Ihre Daten – Sie können in der Zeit zurückreisen, Ereignisse erneut abspielen und sogar alternative Zeitlinien erstellen (Zweige, jemand?).
CQRS: Die Atomspaltung der Datenoperationen
CQRS, oder Command Query Responsibility Segregation (versuchen Sie das fünfmal schnell zu sagen), dreht sich um die Trennung von Verantwortlichkeiten. Es teilt die Operationen Ihrer Anwendung in zwei Lager:
- Commands: Diese ändern Daten (Schreiboperationen)
- Queries: Diese rufen Daten ab (Leseoperationen)
Durch die Trennung dieser Verantwortlichkeiten können Sie jede Seite unabhängig optimieren. Es ist, als hätte man eine spezialisierte Taskforce für jede Operation – Effizienz in ihrer besten Form.
Axon Framework: Ihr ES/CQRS Sidekick
Die Implementierung von Event Sourcing und CQRS von Grund auf mag so viel Spaß machen wie das Debuggen einer Nullzeiger-Ausnahme. Hier kommt das Axon Framework ins Spiel wie ein koffeinierter Superheld. Es ist ein Java-Framework, das ein robustes Toolkit für die Implementierung dieser Muster bietet, ohne dass Sie sich die Haare raufen müssen.
Axons Superkräfte:
- Aggregate-Verwaltung
- Befehls- und Ereignisverarbeitung
- Ereignisspeicherung
- CQRS-Unterstützung von Haus aus
Denken Sie an Axon als Ihren persönlichen Trainer für Event Sourcing und CQRS. Es führt Sie durch den Prozess, übernimmt die schwere Arbeit und bewahrt Sie vor Anfängerfehlern.
Loslegen: Axon-Setup in 3... 2... 1...
Lassen Sie uns loslegen. Zuerst müssen wir unser Projekt einrichten. Wir verwenden Spring Boot, denn mal ehrlich, wer liebt Spring Boot nicht?
Schritt 1: Abhängigkeiten
Fügen Sie diese zu Ihrer pom.xml
(für Maven-Nutzer) oder build.gradle
(für Gradle-Fans) hinzu:
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
Schritt 2: Konfiguration
Das Schöne an Spring Boot ist, dass es die meiste Arbeit für Sie erledigt. Aber lassen Sie uns eine einfache Konfigurationsklasse hinzufügen, um sicherzustellen, dass alles korrekt verdrahtet ist:
@Configuration
public class AxonConfig {
@Bean
public CommandBus commandBus() {
return SimpleCommandBus.builder().build();
}
@Bean
public EventStorageEngine eventStorageEngine() {
return new InMemoryEventStorageEngine();
}
}
Dies richtet einen einfachen In-Memory-Ereignisspeicher ein. In einer realen Umgebung würden Sie eine robustere Lösung verwenden, aber das funktioniert, um uns den Einstieg zu erleichtern.
Befehle implementieren
Jetzt, da wir unser Axon-Setup haben, erstellen wir unseren ersten Befehl. Wir verwenden ein einfaches Bankbeispiel, denn Geld ist immer interessant.
public class CreateAccountCommand {
@TargetAggregateIdentifier
private final String accountId;
private final BigDecimal initialBalance;
// Konstruktor, Getter, etc.
}
Beachten Sie die @TargetAggregateIdentifier
-Annotation? Das ist Axons Art zu sagen: "Hey, dieses Feld identifiziert das Ziel-Aggregat."
Befehle wie ein Profi handhaben
Erstellen wir nun ein Aggregat, um diesen Befehl zu verarbeiten:
@Aggregate
public class AccountAggregate {
@AggregateIdentifier
private String id;
private BigDecimal balance;
@CommandHandler
public AccountAggregate(CreateAccountCommand command) {
apply(new AccountCreatedEvent(command.getAccountId(), command.getInitialBalance()));
}
@EventSourcingHandler
public void on(AccountCreatedEvent event) {
this.id = event.getAccountId();
this.balance = event.getInitialBalance();
}
}
Hier die Erklärung:
@Aggregate
sagt Axon "Diese Klasse ist eine Aggregatwurzel"@AggregateIdentifier
markiert das Feld, das dieses Aggregat eindeutig identifiziert@CommandHandler
sagt "Verwende diese Methode, um CreateAccountCommand zu verarbeiten"@EventSourcingHandler
wird verwendet, um den Zustand des Aggregats basierend auf Ereignissen zu aktualisieren
Ereignisse verarbeiten
Ereignisse sind das Herzstück von Event Sourcing. Erstellen wir einen Ereignis-Handler, um etwas zu tun, wenn ein Konto erstellt wird:
@Component
public class AccountEventHandler {
@EventHandler
public void on(AccountCreatedEvent event) {
System.out.println("Konto erstellt: " + event.getAccountId() +
" mit Guthaben: " + event.getInitialBalance());
// In einer echten App könnten Sie hier ein Lese-Modell aktualisieren
}
}
Dieser Handler wird automatisch von Axon erkannt und aufgerufen, wann immer ein AccountCreatedEvent
veröffentlicht wird.
Abfragen implementieren
Jetzt, da wir unsere Befehlsseite eingerichtet haben, implementieren wir eine einfache Abfrage, um Kontodetails abzurufen:
public class GetAccountBalanceQuery {
private final String accountId;
// Konstruktor, Getter
}
@Component
public class AccountQueryHandler {
@QueryHandler
public BigDecimal handle(GetAccountBalanceQuery query) {
// In einer echten App würden Sie dies aus einem Lese-Modell abrufen
return BigDecimal.TEN; // Jeder startet mit 10 €, warum nicht?
}
}
Um diese Abfrage zu verwenden:
@Autowired
private QueryGateway queryGateway;
public void someMethod() {
BigDecimal balance = queryGateway.query(
new GetAccountBalanceQuery("account123"),
BigDecimal.class
).join();
}
Sagas und verteilte Systeme
Sagas in Axon sind wie die Regisseure eines komplexen Stücks. Sie koordinieren langlaufende Geschäftstransaktionen über mehrere Aggregate hinweg. Erstellen wir eine einfache Saga, die auf die Kontoerstellung reagiert:
@Saga
public class AccountManagementSaga {
@StartSaga
@SagaEventHandler(associationProperty = "accountId")
public void handle(AccountCreatedEvent event) {
// Starten Sie einen Geschäftsprozess
System.out.println("Prozess für neues Konto starten: " + event.getAccountId());
}
@EndSaga
@SagaEventHandler(associationProperty = "accountId")
public void handle(AccountClosedEvent event) {
// Beenden Sie die Saga
System.out.println("Konto geschlossen, Saga beenden: " + event.getAccountId());
}
}
Debugging: Wenn Ereignisse aus der Reihe tanzen
Das Debuggen von eventbasierten Systemen kann knifflig sein. Axon Server (Axons optionales, aber leistungsstarkes Ereignisspeicher- und Nachrichten-Routing-Plattform) bietet eine schöne Benutzeroberfläche zum Inspizieren von Befehlen, Ereignissen und Abfragen. Aber auch ohne es können Sie Ihrem Ereignis-Handler Logging hinzufügen:
@EventHandler
public void on(AccountCreatedEvent event) {
log.info("Konto erstellt: {}", event);
// Rest Ihrer Handler-Logik
}
Best Practices: Die Fallstricke vermeiden
- Halten Sie Aggregate klein: Sie sollten ein einzelnes Geschäftskonzept darstellen.
- Seien Sie vorsichtig mit der Ereignisversionierung: Sobald ein Ereignis gespeichert ist, sollte sich seine Struktur nicht ändern.
- Verwenden Sie Snapshots für große Ereignisströme: Axon unterstützt dies von Haus aus.
- Setzen Sie keine Geschäftslogik in Ereignis-Handler: Sie sollten sich auf die Aktualisierung des Lese-Modells konzentrieren.
- Verwenden Sie aussagekräftige Ereignisnamen:
UserRegistered
ist besser alsUserEvent1
.
Zusammenfassung: Sie sind jetzt ein Axon-Anwender!
Herzlichen Glückwunsch! Sie haben gerade Ihre ersten Schritte in die Welt von Event Sourcing und CQRS mit dem Axon Framework gemacht. Wir haben die Grundlagen behandelt, aber es gibt noch so viel mehr zu entdecken. Axon bietet eine robuste Grundlage für den Aufbau skalierbarer, ereignisgesteuerter Systeme, die sich mit den Anforderungen Ihres Unternehmens weiterentwickeln können.
Denken Sie daran, mit großer Macht kommt große Verantwortung. Event Sourcing und CQRS sind keine Allheilmittel – sie fügen Komplexität hinzu, die möglicherweise nicht für jede Anwendung erforderlich ist. Aber für die richtigen Anwendungsfälle können sie bahnbrechend sein.
Gehen Sie nun verantwortungsbewusst mit Event Sourcing um! Und wenn Sie sich dabei ertappen, wie Sie mit Ihrer Gummiente über Aggregatgrenzen sprechen, machen Sie sich keine Sorgen – das ist in der Axon-Welt völlig normal.
"In der Welt der ereignisgesteuerten Systeme ist jeder Fehler nur eine Gelegenheit für ein neues Ereignis." - Anonymer Entwickler (wahrscheinlich)
Viel Spaß beim Programmieren, und mögen Ihre Ereignisse immer in der richtigen Reihenfolge sein!