Spring Application Events

SkillAI & models

Spring Application Events for Spring Boot 3.x. Covers ApplicationEventPublisher, @EventListener, @TransactionalEventListener, custom events, async events, and event-driven architecture patterns.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Spring Application Events skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/backend-frameworks/spring-events/SKILL.md and read by ahel’s review.

Quick Start

// Custom Event (POJO - preferred)
public record OrderCreatedEvent(
    Long orderId,
    Long customerId,
    BigDecimal totalAmount,
    Instant createdAt
) {}

// Publisher
@Service
@RequiredArgsConstructor
public class OrderService {

    private final ApplicationEventPublisher eventPublisher;

    @Transactional
    public Order createOrder(CreateOrderRequest request) {
        Order order = orderRepository.save(new Order(request));
        eventPublisher.publishEvent(new OrderCreatedEvent(
            order.getId(), order.getCustomerId(),
            order.getTotalAmount(), order.getCreatedAt()
        ));
        return order;
    }
}

// Listener
@Component
@Slf4j
public class OrderEventListener {

    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        log.info("Order created: {}", event.orderId());
    }
}

@EventListener

@Component
public class EventListeners {

    // Basic listener
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        log.info("Processing order: {}", event.orderId());
    }

    // Conditional listener
    @EventListener(condition = "#event.totalAmount > 1000")
    public void handleLargeOrder(OrderCreatedEvent event) {
        notifyManager(event);
    }

    // Ordered execution
    @EventListener
    @Order(1)  // Executed first
    public void validateOrder(OrderCreatedEvent event) { }

    @EventListener
    @Order(2)  // Executed second
    public void processOrder(OrderCreatedEvent event) { }

    // Multiple event types
    @EventListener({OrderCreatedEvent.class, OrderUpdatedEvent.class})
    public void handleOrderChange(Object event) { }
}

Event Chain (Publish New Event from Listener)

@EventListener
public NotificationEvent handleOrderCreated(OrderCreatedEvent event) {
    return new NotificationEvent(event.customerId(), "Order created!");
}

@EventListener
public Collection<Object> handleOrderShipped(OrderShippedEvent event) {
    return List.of(
        new NotificationEvent(event.customerId(), "Order shipped!"),
        new AnalyticsEvent("order_shipped", event.orderId())
    );
}

Custom Events

// Generic event
public class EntityEvent<T> {
    private final T entity;
    private final EventType type;
    private final Instant timestamp = Instant.now();

    public enum EventType { CREATED, UPDATED, DELETED }
}

// Generic publisher
@Component
public class EntityEventPublisher {
    private final ApplicationEventPublisher publisher;

    public <T> void publishCreated(T entity) {
        publisher.publishEvent(new EntityEvent<>(entity, EventType.CREATED));
    }
}

// Typed listener
@EventListener
public void handleUserEvent(EntityEvent<User> event) {
    switch (event.getType()) {
        case CREATED -> handleUserCreated(event.getEntity());
        case UPDATED -> handleUserUpdated(event.getEntity());
    }
}

Full Reference: See transactional.md for @TransactionalEventListener, Async Events.


@TransactionalEventListener

// Execute AFTER transaction commit (default)
@TransactionalEventListener
public void handleAfterCommit(OrderCreatedEvent event) {
    emailService.sendOrderConfirmation(event.orderId());
}

// Execute AFTER rollback
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleAfterRollback(OrderCreatedEvent event) {
    alertService.notifyRollback(event);
}

// Execute BEFORE commit
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleBeforeCommit(OrderCreatedEvent event) {
    validateOrderBeforeCommit(event);
}

// Fallback if no transaction
@TransactionalEventListener(fallbackExecution = true)
public void handleWithFallback(OrderCreatedEvent event) { }

Full Reference: See patterns.md for Domain Events, Aggregate Root, Event Store.


Best Practices

  • ✅ Use @TransactionalEventListener for side effects
  • ✅ Use @Async for non-critical operations
  • ✅ Implement retry for fallible listeners
  • ✅ Use immutable events (records)
  • ✅ Define order with @Order if needed
  • ❌ Don't modify state in sync listeners
  • ❌ Don't assume execution order without @Order

Production Checklist

  • Event classes immutabili
  • TransactionalEventListener for external calls
  • Async for non-critical operations
  • Error handling implemented
  • Retry for transient operations
  • Monitoring events

When NOT to Use This Skill

  • Distributed events - Use spring-kafka or spring-amqp
  • Guaranteed delivery - Use messaging systems
  • Event sourcing - Consider Axon Framework

Common Pitfalls

ErrorCauseSolution
Listener not executedMissing @ComponentAdd annotation
Event lost on rollbackUsing @EventListenerUse @TransactionalEventListener
DeadlockSync listener calls same serviceUse @Async
Exception hiddenAsync voidImplement error handler

Anti-Patterns

Anti-PatternProblemSolution
Sync events in transactionLong transactionsUse @Async or @TransactionalEventListener
Circular event publishingInfinite loopGuard with flags
Heavy processing in syncBlocks publisherUse async listeners
Modifying event after publishShared state issuesMake events immutable

Quick Troubleshooting

ProblemDiagnosticFix
Listener not invokedCheck @EventListenerVerify component scanned
Transaction not committedCheck event phaseUse AFTER_COMMIT
Async not workingCheck @EnableAsyncAdd to config
Order mattersListeners randomUse @Order

Reference Files

FileContent
transactional.md@TransactionalEventListener, Async Events, Lifecycle
patterns.mdDomain Events, Aggregate Root, Event Store

External Documentation

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
spring-events
Source
github.com/claude-dev-suite/claude-dev-suite