Application events inside one service

Spring Boot · lesson 24 of 39 · 3 min read

Decouple beans with published events, and fire side effects only after the commit.

Open this lesson in the learning hub

Key points

  • Publish with ApplicationEventPublisher. Any bean with an @EventListener for that type receives it.
  • A plain listener is synchronous: it runs on the publishing thread, inside the same transaction.
  • So an email sent from a plain listener can go out for an order whose transaction then rolls back.
  • @TransactionalEventListener(phase = AFTER_COMMIT) waits until the data is actually committed.
  • Add @Async to move a listener onto another thread - it then cannot affect the publisher at all.
  • Events are in-process only. Crossing a service boundary needs a broker, not an ApplicationEvent.

Example

public record OrderPlaced(long orderId, String customerEmail) { }

@Service
class CheckoutService {

    private final ApplicationEventPublisher events;

    CheckoutService(ApplicationEventPublisher events) { this.events = events; }

    @Transactional
    public void checkout(Cart cart) {
        Order order = orders.save(Order.from(cart));
        events.publishEvent(new OrderPlaced(order.getId(), order.getEmail()));
        // still inside the transaction here - nothing is committed yet
    }
}

@Component
class ReceiptListener {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    void onOrderPlaced(OrderPlaced event) {
        mail.sendReceipt(event.customerEmail());   // the order really exists now
    }

    @EventListener                                 // runs BEFORE the commit
    void audit(OrderPlaced event) {
        audits.record(event);                      // fine: it shares the same rollback
    }
}

Publish inside the transaction, but do anything the outside world can see only after the commit.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Boot course, and every lesson in it is listed on the Spring Boot contents page.