spring-events
Spring Application Events for Spring Boot 3.x. Covers ApplicationEventPublisher, @EventListener, @TransactionalEventListener, custom events, async events, and event-driven architecture patterns. USE WHEN: user mentions "spring events", "ApplicationEventPublisher", "@EventListener", "@TransactionalEventListener", "event-driven Spring", "domain events" DO NOT USE FOR: external messaging - use `spring-amqp` or `spring-kafka`, distributed events - use messaging systems
What this skill does
# Spring Application Events
## Quick Start
```java
// 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
```java
@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)
```java
@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
```java
// 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](transactional.md) for @TransactionalEventListener, Async Events.
---
## @TransactionalEventListener
```java
// 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](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
| Error | Cause | Solution |
|-------|-------|----------|
| Listener not executed | Missing @Component | Add annotation |
| Event lost on rollback | Using @EventListener | Use @TransactionalEventListener |
| Deadlock | Sync listener calls same service | Use @Async |
| Exception hidden | Async void | Implement error handler |
---
## Anti-Patterns
| Anti-Pattern | Problem | Solution |
|--------------|---------|----------|
| Sync events in transaction | Long transactions | Use @Async or @TransactionalEventListener |
| Circular event publishing | Infinite loop | Guard with flags |
| Heavy processing in sync | Blocks publisher | Use async listeners |
| Modifying event after publish | Shared state issues | Make events immutable |
---
## Quick Troubleshooting
| Problem | Diagnostic | Fix |
|---------|------------|-----|
| Listener not invoked | Check @EventListener | Verify component scanned |
| Transaction not committed | Check event phase | Use AFTER_COMMIT |
| Async not working | Check @EnableAsync | Add to config |
| Order matters | Listeners random | Use @Order |
---
## Reference Files
| File | Content |
|------|---------|
| [transactional.md](transactional.md) | @TransactionalEventListener, Async Events, Lifecycle |
| [patterns.md](patterns.md) | Domain Events, Aggregate Root, Event Store |
---
## External Documentation
- [Application Events](https://docs.spring.io/spring-framework/reference/core/beans/context-introduction.html#context-functionality-events)
- [TransactionalEventListener](https://docs.spring.io/spring-framework/reference/data-access/transaction/event.html)
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.