Anwendungsereignisse
Komponenten in-process entkoppeln, indem man Ereignisse veröffentlicht und darauf lauscht - der Einstieg in ereignisgesteuertes Design.
Deutsche Übersetzung in Arbeit
Diese Lektion ist noch nicht ins Deutsche übersetzt und wird daher auf Englisch angezeigt. Der Rest der Seite ist vollständig lokalisiert.
Auf dieser Seite
Before reaching for a message broker like Kafka, Spring gives you event-driven design inside a single application, for free. Application events let one component announce that something happened, and other components react - without the two ever referencing each other. It's the gateway drug to event-driven architecture, and often all you need.
Publish and listen
When BookVault records a loan, several things might need to happen: send a confirmation,
update a "popular books" counter, log an audit entry. Rather than the LendingService
calling each of those directly (coupling it to all of them), it publishes an event:
record BookBorrowedEvent(String isbn, Long memberId) {}
@Service
class LendingService {
private final ApplicationEventPublisher events;
Loan borrow(String isbn, Long memberId) {
// ... reserve a copy, save the loan ...
events.publishEvent(new BookBorrowedEvent(isbn, memberId)); // announce it
return loan;
}
}Interested components just listen:
@Component
class BorrowNotifier {
@EventListener
void onBorrow(BookBorrowedEvent event) {
// send a "you borrowed a book" notification
}
}The LendingService has no idea who's listening - you can add a new listener tomorrow
without touching it at all.
Coupling the borrow logic to every follow-up action is like a phone tree: the first person must know and call everyone, and adding a person means editing the list. Events are a notice board: you pin up "a book was borrowed," and anyone who cares reads it and acts. The publisher never needs to know who's watching - new subscribers just start reading the board.
Tie events to the transaction
There's a subtlety with events fired inside a database transaction. If you notify a member
"you borrowed a book" but the transaction then rolls back, you've lied to them. The fix
is @TransactionalEventListener, which runs the listener only after the transaction
commits:
@Component
class BorrowNotifier {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
void onBorrow(BookBorrowedEvent event) {
// guaranteed the loan really was committed before we notify
}
}Pair it with @Async and the notification runs after commit and off the request thread -
exactly what BookVault does for its borrow notifications.
In-process first, broker later
Application events decouple components within one app; a broker (Kafka, RabbitMQ) decouples separate services across the network. The programming model is similar, so events are the perfect place to learn event-driven thinking before you distribute it. When BookVault later splits into services, that in-process event becomes a message on a topic.
BookVault publishes a BookBorrowedEvent inside the transactional borrow method, and a
listener emails the member. Occasionally a borrow fails after the event is prepared and the
transaction rolls back - yet members still got emails. Which listener annotation fixes this,
and why?
What do Spring application events achieve?
Key takeaways
- Application events decouple components in-process: publish with ApplicationEventPublisher, react with @EventListener.
- The publisher never references its listeners, so you add new reactions without changing it.
- @TransactionalEventListener(AFTER_COMMIT) runs a listener only after the transaction commits - so you never act on a rolled-back change.
- Combine it with @Async to handle the event after commit and off the request thread.
- In-process events are the natural first step toward broker-based messaging between services.