Loslegen
Javaneer
Zurück zur Stufe
Modul 6·Reaktiv & Messaging

Anwendungsereignisse

Komponenten in-process entkoppeln, indem man Ereignisse veröffentlicht und darauf lauscht - der Einstieg in ereignisgesteuertes Design.

16 Min. LesezeitFortgeschritten

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.

A notice board, not a phone tree

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.

Notify only on real borrows

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.
War diese Lektion hilfreich?
Diese Seite auf GitHub bearbeiten