Los eventos de aplicación permiten que un módulo anuncie que algo ha ocurrido sin conocer a todos los módulos interesados. Esto reduce dependencias directas y facilita añadir nuevos consumidores.
Un componente publica el evento mediante ApplicationEventPublisher:
@Service
class OrderManagement {
private final ApplicationEventPublisher events;
void complete(Order order) {
order.complete();
events.publishEvent(new OrderCompleted(order.getId()));
}
}
Otro módulo puede reaccionar con un listener:
@Component
class InventoryManagement {
@ApplicationModuleListener
void on(OrderCompleted event) {
// Actualizar la reserva de stock.
}
}
Las publicaciones de eventos son síncronas por defecto. Un listener puede ejecutarse dentro de la transacción de quien publicó, lo que mantiene una única unidad de consistencia, pero también amplía esa transacción y puede hacer que falle si el listener falla.
Con @TransactionalEventListener y @Async se puede procesar el evento después del commit, fuera de la transacción original. Esto desacopla el trabajo secundario, pero existe riesgo de perder la publicación si el proceso cae entre el commit y la ejecución del listener.
@ApplicationModuleListener es una anotación abreviada de Spring Modulith para la forma habitual de consumir eventos de módulo de manera asíncrona y transaccional.
El Event Publication Registry registra, en la transacción que publica el evento, una entrada por listener transaccional. Si el listener termina correctamente, la publicación queda completada; si falla, queda pendiente para poder inspeccionarla o reintentarse.
Desde Spring Modulith 2.0, las publicaciones tienen estados como PUBLISHED, PROCESSING, COMPLETED, FAILED y RESUBMITTED. El registro incluye información de intentos y reenvíos. Un monitor puede marcar como fallidas publicaciones atascadas durante demasiado tiempo, si se configuran los límites de antigüedad.
Las APIs IncompleteEventPublications, FailedEventPublications y CompletedEventPublications permiten reintentar publicaciones pendientes o fallidas e inspeccionar o limpiar las completadas. El modo de finalización determina si una publicación completada se conserva, se elimina o se archiva.
El registro requiere almacenamiento transaccional. Spring Modulith ofrece integraciones para JPA, JDBC, MongoDB y Neo4j, entre otras, con starters asociados.
Un evento interno puede interesar a sistemas externos. La externalización selecciona eventos, prepara el mensaje y determina el destino en el broker.
La anotación @Externalized permite marcar eventos y especificar un destino. Hay integraciones para Kafka, AMQP, JMS y canales de Spring Messaging. Se pueden personalizar la selección, el mapeo del evento, las cabeceras y las claves de enrutamiento.
La externalización integrada se apoya en listeners y en el registro de publicaciones para permitir reintentos. Si se necesitan garantías y capacidades avanzadas del patrón outbox, Spring Modulith 2.1 documenta integraciones con Namastack Outbox y JobRunr.
Con @ApplicationModuleTest se puede inyectar PublishedEvents o AssertablePublishedEvents y comprobar qué eventos se publicaron durante una operación. Para probar escenarios completos con listeners y procesamiento asíncrono, se recomienda la API Scenario, descrita en la documentación de pruebas de módulos.