← Back to list

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…

Talha Aydeger in TOM Tech · 2026-04-06 07:42 · 37 claps · 2.6 min read
#spring-boot #producer #eventbus #microservices
Open on Medium ↗
Wiki topics: 🏛️ · Architecture

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:

  1. Event — A plain Java object representing what happened
  2. Publisher — The component that fires the event
  3. 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 commit
  • AFTER_ROLLBACK — after rollback
  • AFTER_COMPLETION — after commit or rollback
  • BEFORE_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 {
}
  1. Add @Async to 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