Spring Cloud Stream und Event-getriebene Microservices
Spring Cloud Stream abstrahiert Messaging-Systeme über Binder und ein funktionales Programmiermodell für Producer, Consumer und Processor.
Fachliche Einordnung
Event-driven Architecture braucht klare Event-Verträge, Consumer Groups, Partitionierung, Retry, DLQ und Idempotenz. Cloud Stream standardisiert viele technische Muster.
Enterprise-Merksatz: Spring Cloud Stream abstrahiert Messaging-Systeme über Binder und ein funktionales Programmiermodell für Producer, Consumer und Processor.
Technische Darstellung
Kernkonzepte
- Binder für Kafka, RabbitMQ, Pulsar und weitere Systeme.
- Function, Consumer und Supplier als Binding-Ziele.
- Destination, Binding, Message und Header.
- Consumer Groups und Partitionierung.
- DLQ, Retry und Fehlerkanäle.
Wann einsetzen?
- Du willst austauschbare Messaging-Binder.
- Du baust fachliche Events zwischen Services.
- Du brauchst Consumer Groups und skalierende Verarbeitung.
Typische Fehler und Risiken
- Event Payloads ohne Versionierung.
- Consumer nicht idempotent.
- Event-Streams als synchrones RPC missbrauchen.
Legacy- und Modernisierungssicht
JMS-Queues können schrittweise auf Kafka/RabbitMQ/Pulsar-Binder migriert werden; Fachereignisse sollten explizit und versioniert werden.
Ausführliches Beispiel
Das Beispiel zeigt bewusst nicht nur Annotationen, sondern auch die Verantwortung der Schicht. In echten Projekten sollte der technische Spring-Code an Adapter- oder Konfigurationsrändern bleiben, während die Fachlogik testbar und möglichst frameworkarm bleibt.
@Configuration
class OrderEventStreamConfiguration {
@Bean
Consumer<Message<OrderCreatedEvent>> reserveInventory(InventoryService inventory) {
return message -> {
String eventId = message.getHeaders().getId().toString();
inventory.reserveIfNotProcessed(eventId, message.getPayload());
};
}
}
# application.yml
spring:
cloud:
function:
definition: reserveInventory
stream:
bindings:
reserveInventory-in-0:
destination: order.created.v1
group: inventory-service
Checkliste für Reviews
- Ist die Verantwortung des Bausteins klar: Framework steuert Lebenszyklus, Library wird gezielt benutzt?
- Ist die Fachlogik außerhalb von Controller, Listener, Repository-Implementierung oder Konfiguration?
- Sind Fehlerfälle, Timeouts, Security, Monitoring und Tests sichtbar modelliert?
- Gibt es klare Grenzen zwischen DTO, Domäne, Persistence und Infrastruktur?