user
04/13/2026, 10:22 AMJames Fredley
04/15/2026, 7:40 PMApplicationEventPublisher (Recommended)
Since Grails 3.x is built on Spring Boot, the native Spring eventing mechanism is the most stable and future-proof choice. It requires no extra dependencies and is actively maintained as part of the core framework.
How it works:
// Define a custom event
class OrderPlacedEvent extends ApplicationEvent {
Order order
OrderPlacedEvent(Object source, Order order) {
super(source)
this.order = order
}
}
// Publish the event
@Service
class OrderService {
@Autowired
ApplicationEventPublisher eventPublisher
void placeOrder(Order order) {
// business logic...
eventPublisher.publishEvent(new OrderPlacedEvent(this, order))
}
}
// Listen for the event
@Service
class NotificationService {
@EventListener
void handleOrderPlaced(OrderPlacedEvent event) {
// handle the event...
}
}
Key benefits:
Zero extra dependencies — it's baked into Spring Boot
Works seamlessly with Grails 3.x and 4.x, making future upgrades easier
Supports synchronous and asynchronous (@Async) event handling out of the box
• Full transaction support via @TransactionalEventListener, which is extremely useful for post-commit hooks
• Well-documented with a huge community
Option 2: Grails grails-events Plugin (Reactor-based)
Grails 3.x does have an official events plugin based on Project Reactor (org.grails.plugins:grails-events). It's worth considering if your application requires reactive, non-blocking event streams.
// In build.gradle
compile "org.grails.plugins:grails-events:latest"
// Publish
eventBus.notify('order.placed', order)
// Listen
@Subscriber('order.placed')
void onOrderPlaced(Order order) { ... }
However, be aware of the trade-offs:
• The plugin has seen inconsistent maintenance across Grails minor versions
• It introduces Reactor as a dependency, adding complexity if you don't need reactive streams
• Community support is narrower compared to core Spring eventing
Recommendation
Go with native Spring ApplicationEventPublisher for the vast majority of use cases. Here's a simple decision guide:
Scenario Recommended Approach Domain event notifications, service decoupling Spring ApplicationEventPublisher Post-commit / transactional events Spring @TransactionalEventListener Async background processing Spring @Async + @EventListener Reactive/non-blocking event streams Reactor-based grails-events plugin Simple pub/sub within the app Spring ApplicationEventPublisher
Migration Tips from Spring Events Plugin 1.2
The old plugin's @Listener annotation maps directly to Spring's @EventListener
Replace grailsEvents.publishEvent(...) calls with applicationEventPublisher.publishEvent(...)
If you were using synchronous listeners, the behavior is identical in Spring's default mode
• For async listeners, add @Async and enable it with @EnableAsync on your Application class
This path gives you the cleanest upgrade, the least risk, and the best compatibility with any future Grails or Spring Boot upgrades.