Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring application events: local delivery is not a durable queue

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

An application event delivers a notification to listeners registered in the current application context.

Download Spring source kit

This lesson uses the downloadable source kit: Java 21, Spring Boot 4.0.8 and its managed Spring Framework 7 dependencies. The version is pinned for repeatable builds.

Keep the delivery promise small

ContainerContracts publishes receipt-created and its ordinary listener increments a counter before publishEvent returns. This local fixture verifies synchronous default delivery. A listener that performs slow I/O would therefore delay the publisher unless delivery is configured differently.

An event name does not persist work. If the JVM stops after a payment commits but before a notification completes, this local counter cannot replay the notification. A business promise of eventual delivery needs durable state and an idempotent consumer.

Transaction timing is another boundary

A regular listener can run before a surrounding database transaction commits. Reading the event as proof of committed data is therefore unsafe. Transaction-bound listeners require their own phase and rollback tests; they are a separate extension not implemented by this fixture.

The kit uses a string payload to expose delivery timing. A real event should carry a stable identifier and only the data its consumer needs. Passing a mutable entity graph into an asynchronous listener creates ownership and persistence-lifetime problems.

Checked source

Java
AtomicInteger messages = new AtomicInteger();
context.addApplicationListener((ApplicationListener<PayloadApplicationEvent<String>>) event -> messages.incrementAndGet());
context.publishEvent("receipt-created");
System.out.println(messages.get());

Test the boundary

Run mvn test in the source-kit directory. CoreBoundaryTest checks the behavior described here. Java excerpts belong to the named source-kit classes; they are not independent source files unless the complete class is shown.

Costs and boundaries

Publisher cost includes synchronous listener work in this fixture. Async delivery adds queue capacity and cancellation costs; neither form provides broker persistence.

Common Mistakes

  • A local event is not durable messaging.
  • A published event is not proof that a database transaction committed.
  • Do not transfer mutable request state without an ownership rule.

Read next

Transactions, Async boundaries, Java bounded executors: test saturation and rejected work.

Extend this boundary

Continue with Spring transaction events: run a listener after commit without claiming durability.

spring
spring-boot
application-events
Storage details