Core dependency injection interfaces and components for the Micronaut Framework
—
Micronaut's event system provides a powerful mechanism for decoupled communication between components through application lifecycle events and custom business events. It supports both synchronous and asynchronous event processing.
Interface for publishing application events to registered listeners.
public interface ApplicationEventPublisher<T> {
void publishEvent(T event);
Future<Void> publishEventAsync(T event);
}Interface for listening to application events.
public interface ApplicationEventListener<E> {
void onApplicationEvent(E event);
default boolean supports(E event) { return true; }
}Generic event listener interface for method-level event handling.
@Target({METHOD})
@Retention(RUNTIME)
public @interface EventListener {
boolean async() default false;
}Fired when the application context starts up.
public class StartupEvent extends ApplicationEvent {
public StartupEvent(ApplicationContext source);
public ApplicationContext getSource();
}More specific startup event with additional context.
public class ApplicationStartupEvent extends ApplicationEvent {
public ApplicationStartupEvent(Application source);
public Application getSource();
}Fired when the application context shuts down.
public class ShutdownEvent extends ApplicationEvent {
public ShutdownEvent(ApplicationContext source);
public ApplicationContext getSource();
}Fired when a bean is created.
public class BeanCreatedEvent<T> extends ApplicationEvent {
public BeanCreatedEvent(BeanContext beanContext, BeanDefinition<T> beanDefinition, T bean);
public BeanDefinition<T> getBeanDefinition();
public T getBean();
}Fired when a bean is fully initialized.
public class BeanInitializedEvent<T> extends ApplicationEvent {
public BeanInitializedEvent(BeanContext beanContext, BeanDefinition<T> beanDefinition, T bean);
public BeanDefinition<T> getBeanDefinition();
public T getBean();
}Fired when a bean is destroyed.
public class BeanDestroyedEvent<T> extends ApplicationEvent {
public BeanDestroyedEvent(BeanContext beanContext, BeanDefinition<T> beanDefinition, T bean);
public BeanDefinition<T> getBeanDefinition();
public T getBean();
}import io.micronaut.context.event.ApplicationEventPublisher;
import jakarta.inject.Singleton;
import jakarta.inject.Inject;
@Singleton
public class OrderService {
private final ApplicationEventPublisher<OrderEvent> eventPublisher;
@Inject
public OrderService(ApplicationEventPublisher<OrderEvent> eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void createOrder(Order order) {
// Process order
order.setStatus(OrderStatus.CREATED);
// Publish event
OrderCreatedEvent event = new OrderCreatedEvent(order);
eventPublisher.publishEvent(event);
}
public void cancelOrder(String orderId) {
// Cancel order logic
Order order = findOrder(orderId);
order.setStatus(OrderStatus.CANCELLED);
// Publish cancellation event
OrderCancelledEvent event = new OrderCancelledEvent(order);
eventPublisher.publishEvent(event);
}
}import io.micronaut.context.event.ApplicationEventPublisher;
import jakarta.inject.Singleton;
import java.util.concurrent.Future;
@Singleton
public class NotificationService {
private final ApplicationEventPublisher<NotificationEvent> eventPublisher;
@Inject
public NotificationService(ApplicationEventPublisher<NotificationEvent> eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void sendNotification(String message, String recipient) {
NotificationEvent event = new NotificationEvent(message, recipient);
// Publish asynchronously - doesn't block
Future<Void> future = eventPublisher.publishEventAsync(event);
// Optionally handle completion
future.thenRun(() -> {
System.out.println("Notification event published successfully");
}).exceptionally(throwable -> {
System.err.println("Failed to publish notification event: " + throwable.getMessage());
return null;
});
}
}import io.micronaut.context.event.ApplicationEventListener;
import jakarta.inject.Singleton;
@Singleton
public class OrderEventListener implements ApplicationEventListener<OrderCreatedEvent> {
@Override
public void onApplicationEvent(OrderCreatedEvent event) {
Order order = event.getOrder();
System.out.println("Order created: " + order.getId());
// Send confirmation email
sendConfirmationEmail(order);
// Update inventory
updateInventory(order);
}
@Override
public boolean supports(OrderCreatedEvent event) {
// Only handle events for orders over $100
return event.getOrder().getTotal().compareTo(new BigDecimal("100")) > 0;
}
private void sendConfirmationEmail(Order order) {
// Email sending logic
}
private void updateInventory(Order order) {
// Inventory update logic
}
}import io.micronaut.context.event.EventListener;
import jakarta.inject.Singleton;
@Singleton
public class ApplicationEventHandler {
@EventListener
public void onStartup(StartupEvent event) {
System.out.println("Application started: " + event.getSource());
// Initialize caches, warm up connections, etc.
}
@EventListener
public void onShutdown(ShutdownEvent event) {
System.out.println("Application shutting down: " + event.getSource());
// Cleanup resources, save state, etc.
}
@EventListener(async = true) // Asynchronous processing
public void onOrderCreated(OrderCreatedEvent event) {
// This runs in a separate thread
generateOrderReport(event.getOrder());
}
@EventListener
public void onBeanCreated(BeanCreatedEvent<?> event) {
if (event.getBean() instanceof DatabaseService) {
System.out.println("Database service bean created: " + event.getBeanDefinition().getBeanType());
}
}
}import io.micronaut.context.event.ApplicationEventListener;
import jakarta.inject.Singleton;
@Singleton
public class GenericEventLogger implements ApplicationEventListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("Event received: " + event.getClass().getSimpleName() +
" at " + Instant.now());
}
@Override
public boolean supports(ApplicationEvent event) {
// Log all events except bean lifecycle events (too noisy)
return !(event instanceof BeanCreatedEvent ||
event instanceof BeanInitializedEvent ||
event instanceof BeanDestroyedEvent);
}
}import io.micronaut.context.ApplicationEvent;
// Base order event
public abstract class OrderEvent extends ApplicationEvent {
private final Order order;
public OrderEvent(Order order) {
super(order);
this.order = order;
}
public Order getOrder() {
return order;
}
}
// Specific order events
public class OrderCreatedEvent extends OrderEvent {
public OrderCreatedEvent(Order order) {
super(order);
}
}
public class OrderCancelledEvent extends OrderEvent {
private final String reason;
public OrderCancelledEvent(Order order, String reason) {
super(order);
this.reason = reason;
}
public String getReason() {
return reason;
}
}
public class OrderShippedEvent extends OrderEvent {
private final String trackingNumber;
private final String carrier;
public OrderShippedEvent(Order order, String trackingNumber, String carrier) {
super(order);
this.trackingNumber = trackingNumber;
this.carrier = carrier;
}
public String getTrackingNumber() {
return trackingNumber;
}
public String getCarrier() {
return carrier;
}
}// User events
public class UserRegisteredEvent extends ApplicationEvent {
private final User user;
public UserRegisteredEvent(User user) {
super(user);
this.user = user;
}
public User getUser() {
return user;
}
}
public class UserLoginEvent extends ApplicationEvent {
private final String username;
private final String ipAddress;
private final Instant loginTime;
public UserLoginEvent(String username, String ipAddress) {
super(username);
this.username = username;
this.ipAddress = ipAddress;
this.loginTime = Instant.now();
}
// Getters...
}
// Payment events
public class PaymentProcessedEvent extends ApplicationEvent {
private final Payment payment;
private final PaymentResult result;
public PaymentProcessedEvent(Payment payment, PaymentResult result) {
super(payment);
this.payment = payment;
this.result = result;
}
// Getters...
}import io.micronaut.context.event.EventListener;
import jakarta.inject.Singleton;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@Singleton
public class EventAggregator {
private final Map<String, AtomicInteger> eventCounts = new ConcurrentHashMap<>();
@EventListener
public void onOrderEvent(OrderEvent event) {
String eventType = event.getClass().getSimpleName();
eventCounts.computeIfAbsent(eventType, k -> new AtomicInteger(0)).incrementAndGet();
}
@EventListener
public void onUserEvent(UserEvent event) {
String eventType = event.getClass().getSimpleName();
eventCounts.computeIfAbsent(eventType, k -> new AtomicInteger(0)).incrementAndGet();
}
public Map<String, Integer> getEventStats() {
return eventCounts.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().get()
));
}
}import io.micronaut.context.event.EventListener;
import io.micronaut.context.event.ApplicationEventPublisher;
import jakarta.inject.Singleton;
@Singleton
public class OrderProcessingChain {
private final ApplicationEventPublisher<OrderEvent> eventPublisher;
@Inject
public OrderProcessingChain(ApplicationEventPublisher<OrderEvent> eventPublisher) {
this.eventPublisher = eventPublisher;
}
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
Order order = event.getOrder();
// Validate order
if (validateOrder(order)) {
eventPublisher.publishEvent(new OrderValidatedEvent(order));
} else {
eventPublisher.publishEvent(new OrderRejectedEvent(order, "Validation failed"));
}
}
@EventListener
public void onOrderValidated(OrderValidatedEvent event) {
Order order = event.getOrder();
// Process payment
PaymentResult result = processPayment(order);
if (result.isSuccessful()) {
eventPublisher.publishEvent(new OrderPaymentCompletedEvent(order));
} else {
eventPublisher.publishEvent(new OrderPaymentFailedEvent(order, result.getError()));
}
}
@EventListener
public void onPaymentCompleted(OrderPaymentCompletedEvent event) {
Order order = event.getOrder();
// Ship order
String trackingNumber = shipOrder(order);
eventPublisher.publishEvent(new OrderShippedEvent(order, trackingNumber, "UPS"));
}
}import io.micronaut.context.event.EventListener;
import io.micronaut.context.annotation.Requires;
import jakarta.inject.Singleton;
@Singleton
@Requires(property = "analytics.enabled", value = "true")
public class AnalyticsEventProcessor {
@EventListener
public void onUserAction(UserActionEvent event) {
// Only process if analytics is enabled
recordUserAction(event);
}
@EventListener
public void onOrderCompleted(OrderCompletedEvent event) {
recordSale(event.getOrder());
updateRevenueMetrics(event.getOrder());
}
}
@Singleton
@Requires(env = "prod")
public class ProductionEventMonitor {
@EventListener
public void onError(ErrorEvent event) {
// Only monitor errors in production
alertOpsTeam(event);
}
}import io.micronaut.context.event.EventListener;
import jakarta.inject.Singleton;
@Singleton
public class RobustEventHandler {
@EventListener
public void onOrderEvent(OrderEvent event) {
try {
processOrder(event.getOrder());
} catch (PaymentException e) {
System.err.println("Payment processing failed for order: " + event.getOrder().getId());
handlePaymentFailure(event.getOrder(), e);
} catch (InventoryException e) {
System.err.println("Inventory update failed for order: " + event.getOrder().getId());
handleInventoryFailure(event.getOrder(), e);
} catch (Exception e) {
System.err.println("Unexpected error processing order event: " + e.getMessage());
handleGenericFailure(event.getOrder(), e);
}
}
private void handlePaymentFailure(Order order, PaymentException e) {
// Specific payment failure handling
}
private void handleInventoryFailure(Order order, InventoryException e) {
// Specific inventory failure handling
}
private void handleGenericFailure(Order order, Exception e) {
// Generic error handling
}
}Default implementation of ApplicationEventPublisher.
public class DefaultApplicationEventPublisher<T> implements ApplicationEventPublisher<T> {
public DefaultApplicationEventPublisher(BeanContext beanContext);
@Override
public void publishEvent(T event);
@Override
public Future<Void> publishEventAsync(T event);
}Base class for all application events.
public abstract class ApplicationEvent extends EventObject {
private final long timestamp;
public ApplicationEvent(Object source);
public final long getTimestamp();
}Install with Tessl CLI
npx tessl i tessl/maven-io-micronaut--micronaut-inject