javaintermediate

Spring Boot — Application Events

Use Spring's event system for decoupled communication: custom events, async listeners, and ordering.

java
import org.springframework.context.*;
import org.springframework.context.event.*;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.*;
import java.time.Instant;

// Custom event
public record OrderCreatedEvent(String orderId, String userId, double total, Instant timestamp) {
    public OrderCreatedEvent(String orderId, String userId, double total) {
        this(orderId, userId, total, Instant.now());
    }
}

// Publishing events
@Service
class OrderService {
    private final ApplicationEventPublisher publisher;

    OrderService(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void createOrder(String orderId, String userId, double total) {
        // ... save order to DB
        System.out.println("Order created: " + orderId);

        // Publish event (decoupled from listeners)
        publisher.publishEvent(new OrderCreatedEvent(orderId, userId, total));
    }
}

// Listeners — executed in publisher's thread by default
@Component
class EmailNotificationListener {
    @EventListener
    @Order(1) // execute first
    public void onOrderCreated(OrderCreatedEvent event) {
        System.out.printf("[Email] Sending confirmation for order %s to user %s%n",
            event.orderId(), event.userId());
    }
}

@Component
class InventoryListener {
    @EventListener
    @Order(2)
    public void onOrderCreated(OrderCreatedEvent event) {
        System.out.printf("[Inventory] Reserving stock for order %s%n", event.orderId());
    }
}

// Async listener (non-blocking)
@Component
class AnalyticsListener {
    @Async
    @EventListener
    public void onOrderCreated(OrderCreatedEvent event) {
        System.out.printf("[Analytics] Recording order %s ($%.2f) on %s%n",
            event.orderId(), event.total(), Thread.currentThread().getName());
    }
}

// Conditional listener
@Component
class HighValueOrderListener {
    @EventListener(condition = "#event.total() > 100")
    public void onHighValueOrder(OrderCreatedEvent event) {
        System.out.printf("[VIP] High value order %s: $%.2f%n",
            event.orderId(), event.total());
    }
}

// Transaction-bound listener
// @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
// public void afterCommit(OrderCreatedEvent event) {
//     // Only runs after transaction successfully commits
// }

Sponsored

Railway

Use Cases

  • Decoupled event-driven service communication
  • Async notification and side-effect processing
  • Order processing pipelines with event listeners

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.