CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-micronaut--micronaut-inject

Core dependency injection interfaces and components for the Micronaut Framework

Pending
Overview
Eval results
Files

events.mddocs/

Event System

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.

Core Interfaces

ApplicationEventPublisher

Interface for publishing application events to registered listeners.

public interface ApplicationEventPublisher<T> {
    void publishEvent(T event);
    Future<Void> publishEventAsync(T event);
}

ApplicationEventListener

Interface for listening to application events.

public interface ApplicationEventListener<E> {
    void onApplicationEvent(E event);
    default boolean supports(E event) { return true; }
}

EventListener

Generic event listener interface for method-level event handling.

@Target({METHOD})
@Retention(RUNTIME)
public @interface EventListener {
    boolean async() default false;
}

Built-in Application Events

Startup Events

StartupEvent

Fired when the application context starts up.

public class StartupEvent extends ApplicationEvent {
    public StartupEvent(ApplicationContext source);
    public ApplicationContext getSource();
}

ApplicationStartupEvent

More specific startup event with additional context.

public class ApplicationStartupEvent extends ApplicationEvent {
    public ApplicationStartupEvent(Application source);
    public Application getSource();
}

Shutdown Events

ShutdownEvent

Fired when the application context shuts down.

public class ShutdownEvent extends ApplicationEvent {
    public ShutdownEvent(ApplicationContext source);
    public ApplicationContext getSource();
}

Bean Lifecycle Events

BeanCreatedEvent

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();
}

BeanInitializedEvent

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();
}

BeanDestroyedEvent

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();
}

Event Publishing

Publishing Events

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);
    }
}

Asynchronous Event Publishing

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;
        });
    }
}

Event Listening

Interface-based Listeners

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
    }
}

Method-based Listeners

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());
        }
    }
}

Generic Event Listeners

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);
    }
}

Custom Events

Creating Custom Events

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;
    }
}

Business Event Examples

// 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...
}

Event Processing Patterns

Event Aggregation

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()
            ));
    }
}

Event Chain Processing

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"));
    }
}

Conditional Event Processing

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);
    }
}

Error Handling

Event Processing Errors

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
    }
}

Implementation Classes

DefaultApplicationEventPublisher

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);
}

ApplicationEvent

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

docs

annotations.md

application-context.md

bean-definition.md

bean-factory.md

bean-processing.md

bean-providers.md

environment-config.md

events.md

exceptions.md

index.md

scoping.md

tile.json