Spring Boot In-Memory Event Publishing: A Clean Way to Decouple Your Services
Event-driven architecture doesn’t always require Kafka or RabbitMQ. Sometimes, all you need is a lightweight, in-memory event mechanism to…

Spring Boot In-Memory Event Publishing: A Clean Way to Decouple Your Services
Event-driven architecture doesn’t always require Kafka or RabbitMQ. Sometimes, all you need is a lightweight, in-memory event mechanism to decouple your components within a single application. Spring Boot provides exactly that out of the box.
Why In-Memory Events?
Imagine you have an order service that, after placing an order, needs to send a notification, update inventory, and log an audit trail. You could call all these services directly — but that creates tight coupling and makes your code harder to maintain.
Instead, you can publish an event and let interested components react independently.
The Building Blocks
Spring’s event system consists of three parts:
- Event — A plain Java object representing what happened
- Publisher — The component that fires the event
- Listener — The component(s) that react to the event
Step 1: Define Your Event
public record OrderPlacedEvent(
Long orderId,
String customerEmail,
BigDecimal totalAmount
) {}
Step 2: Publish the Event
Inject ApplicationEventPublisher and call publishEvent():
@Service
@RequiredArgsConstructor
public class OrderService {
private final ApplicationEventPublisher eventPublisher;
private final OrderRepository orderRepository;
@Transactional
public Order placeOrder(OrderRequest request) {
Order order = orderRepository.save(mapToOrder(request));
eventPublisher.publishEvent(
new OrderPlacedEvent(order.getId(), request.getEmail(), order.getTotal())
);
return order;
}
}
Step 3: Listen to the Event
An event listener is a Spring-managed component that waits for a specific event and reacts when that event is published. The publisher does not need to know which listener will handle the event or what it will do next. This helps keep the code loosely coupled and easier to maintain.
For example, a service can publish a OrderPlacedEvent, and different listeners can validate the payment, send a notification, or write an audit log. Each listener focuses on a single responsibility, which makes the application cleaner and easier to extend.
Use @TransactionalEventListener or @EventListener on any Spring-managed bean:
@Component
public class OrderAuditListener {
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleBeforeCommit(OrderPlacedEvent event) {
log.info("Writing audit record before commit for order {}", event.getOrderId());
}
}
@Component
public class AuditListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleOrderPlaced(OrderPlacedEvent event) {
// This runs ONLY if the transaction commits successfully
log.info("Audit log: order {} placed", event.getOrderId());
}
}
@EventListener(condition = "#event.totalAmount > 1000")
public void handleHighValueOrder(OrderPlacedEvent event) {
log.info("High value order detected: {}", event.getOrderId());
}
Multiple listeners can react to the same event — they are completely independent of each other.
@EventListener handles an event immediately when it is published, while @TransactionalEventListener handles it according to the surrounding transaction phase such as before commit, after commit, or after rollback.
Available phases:
AFTER_COMMIT(default) — after successful commitAFTER_ROLLBACK— after rollbackAFTER_COMPLETION— after commit or rollbackBEFORE_COMMIT— before the transaction commits
Async Events
By default, events are synchronous — the publisher waits for all listeners to finish. To make them async:
1.Enable async support:
@Configuration
@EnableAsync
public class AsyncConfig {
}
- Add
@Asyncto your listener:
@Component
@Slf4j
public class NotificationListener {
@Async
@EventListener
public void handleOrderPlaced(OrderPlacedEvent event) {
log.info("Sending email asynchronously...");
// this runs in a separate thread
}
}
Be careful: async listeners run outside the original transaction context.
When to Use In-Memory Events
Use When:
- Components are in the same application
- You want to decouple without infrastructure overhead
- Low-latency reactions are important
- Simple pub/sub within a monolith or modular monolith
Avoid When:
- You need cross-service communication
- You need guaranteed delivery / persistence
- Events must survive application restarts
- You need complex routing or dead-letter queues
Summary
Spring Boot’s in-memory event system is a powerful yet underused feature. It helps you:
- Decouple components without adding external dependencies
- Simplify code by separating concerns
- React to domain events cleanly and maintainably
When your application grows and you need durability or cross-service communication, you can always migrate to a message broker. But for many use cases, ApplicationEventPublisher is all you need.
Happy coding!
메타데이터
- post_id
- 4938ee7fc4f9
- slug
- spring-boot-in-memory-event-publishing-a-clean-way-to-decouple-your-services-4938ee7fc4f9
- url
- https://medium.com/tom-tech/spring-boot-in-memory-event-publishing-a-clean-way-to-decouple-your-services-4938ee7fc4f9
- canonical_url
- https://medium.com/tom-tech/spring-boot-in-memory-event-publishing-a-clean-way-to-decouple-your-services-4938ee7fc4f9
- author_url
- https://medium.com/@talha.aydeger
- status
- ok
- fetched_at
- 2026-06-20 20:29:01