====== 03 - Eventos de aplicación ====== 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. ===== 1. Publicar y consumir eventos ===== 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. ===== 2. Registro de publicaciones ===== 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. ===== 3. Externalizar eventos ===== 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**. ===== 4. Pruebas de eventos ===== 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. Los eventos desacoplan al publicador de sus consumidores, pero la asincronía introduce requisitos de fiabilidad: persistencia de publicaciones, reintentos y tratamiento de fallos. ===== Referencia ===== * [Documentación oficial: Working with Application Events](https://docs.spring.io/spring-modulith/reference/events.html) (Spring Modulith 2.1.1).