Uso de Eventos con Spring

Eventos-spring-boot

Eventos-spring-boot


En este artículo vamos tratar el uso de Eventos con Spring, cómo los ejecutamos y en qué casos nos va a ayudar en nuestras aplicaciones y desarrollos.

Si queremos consumir un evento, podemos escribir un «listener» de ese evento dentro del origen del evento, pero esto haría nuestro código dependiente y fuertemente acoplado a la lógica del evento.

Los eventos en Spring tienen como objetivo ser flexibles y dinámicos de modo que te puedas suscribir al evento desde cualquier punto sin necesidad de realizar desarrollos adicionales o estar acoplado al código del evento. Podemos tener tantos «listeners» como queramos para ese evento.

Los eventos de Spring que son proporcionados por el ApplicationContext, la cual nos facilita toda la lógica y codificación necesaria para suscribirnos a cualquier evento.

¿Por qué usar Eventos de Spring?

Una de las primeras preguntas que te harás, es por qué hacer uso de Eventos en lugar de llamar al código directamente.

Si llamamos a un método directamente estamos haciendo una operación directa que queremos que se haga siempre de manera secuencia en función de una lógica. No nos importa el estado en que se encuentra el flujo de ejecución, siempre se procesará una lógica en concreto.

En cambio, cuando hacemos uso de los Eventos de Spring los suscritos a ese eventos serán informados pudiéndose tomar diferentes acciones. Por ejemplo, un uso bastante frecuente con los eventos es poder seguir con la ejecución en otro hilo a parte, por ejemplo para realizar un guardado en otra base de datos, enviar un email o realizar otros procesos pesados.

Publicar un evento con ApplicationEvent

Para hacer uso de Eventos con Spring, vamos a utilizar el ApplicationEventPublisher, el cual nos dará una interfaz que nos permitirá crear nuestros eventos.

La interfaz ApplicationEventPublisher se encargará de publicar un evento que será consumido por todos aquellos que se encuentren escuchando.

Vamos a ver con un ejemplo como sería el proceso.

@Component
@RequiredArgsConstructor
class Publisher {
  
  private final ApplicationEventPublisher publisher;

  void publishEvent(final String name) {
    // Publicamos el nuevo evento
    publisher.publishEvent(new UserEvent(name));
    
  }
}

En el fragmento de código anterior hemos creado un evento a través de ApplicationEventPublisher el cual lo inyectamos haciendo uso del constructor proporcionado por Lombok.

Leer un Evento de Spring

Una vez se ha creado y publicado nuestro Evento es momento de leerlo, para ello creamos un «listener» con la anotación @EventListener.

La anotación @EventListener automáticamente registra un ApplicationListener. No es necesario configuración adicional, el método que tenga la anotación @EventListener podrá escuchar los eventos a los que se suscriba sin mayor codificación.

Además la anotación @EventListener nos permite hacer uso de SpEL y parametrizar en función del tipo de Evento que queremos escuchar por ejemplo: ContextStartedEvent.class, ContextRefreshedEvent.class.

@Component
class UserListener {

  @EventListener(UserEvent.class)
  public void createUserEvent(UserEvent user) {

    executeEvent(user);

  }
}

O por ejemplo aplicando SpEL:

@Component
class UserListener {

  @EventListener(condition = "#userEvent.success")
  public void createUserEvent(UserEvent user) {

    executeEvent(user);

  }
}

Eventos Asíncronos con Spring

Tenemos que tener en cuenta que los eventos de Spring son síncronos, por lo que no se va a crear ningún hilo a parte o se ejecutará de manera paralela. Es decir, todo evento que se lancé tendrá un proceso secuencial.

Para poder tener eventos asíncronos con Spring vamos a hacer uso de los Futuros de Java o uso de @Async con Spring.

Vamos a ver como podríamos lanzar un evento asíncrono haciendo uso de un completableFuture:

@Component
@RequiredArgsConstructor
class Publisher {
  
  private final ApplicationEventPublisher publisher;

  void publishEvent(final String name) {

    log.debug("MAIN THREAD {}", Thread.currentThread().getName());
    UserEvent userEvent = new UserEvent();
    userEvent.setName(name); 
    CompletableFuture.runAsync(() -> eventPublisher.publishEvent(userEvent));
  }
}  
  

  @EventListener(UserEvent.class)
  public void createAssetCoveragePolicy(UserEvent userEvent) {

    log.debug("THREAD WORKER {}", Thread.currentThread().getName());

    executeEvent(userEvent);

  }

 private void executeEvent(UserEvent userEvent) {


    EventFactory.getOperationType(Operation.SAVE).operation(userEvent);

}

En el ejemplo de código anterior creamos un flujo completo de un evento, lo creamos y envíamos hasta su recepción. Lo que hacemos es que al publicar se cree un nuevo hilo de manera que ese Thread se encarga del tratamiento de ese evento.

Evento Transaction-Bound en Spring

Cuando trabajamos con Eventos uno de los puntos fuertes que podemos aplicar es hacer uso del Transaction-Bound es decir, aplicar y trabajar con transacciones.

Para hacer uso de las transacciones con los Evento de Spring utilizaremos la anotación @TransactionalEventListener, la cual nos va a permitir gestionar el evento según el ciclo de vida de la transacción.

Podemos encontrar diferentes fases al utilizar la anotación TransactionalEventListener:

  • AFTER_COMMIT: Un evento se lanzará si la transacción se ha completado. Es la false por defecto.
  • AFTER_ROLLBACK: Si la transacción tiene un roll-back.
  • AFTER_COMPLETION: Si la transacción se ha completado.
  • BEFORE_COMMIT se lanza el evento justo antes que se haga un commit.

Junto con la anotación @TransactionalEventListener, podemos hacer uso de cualquiera de las etapas anteriores para lanzar nuestro evento.

Por ejemplo si continuamos con el ejemplo anterior:

  @EventListener(UserEvent.class)
  @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
  public void createAssetCoveragePolicy(UserEvent userEvent) {

    log.debug("MAIN THREAD {}", Thread.currentThread().getName());

    CompletableFuture.runAsync(() -> executeEvent(userEvent));

  }

Conclusión

En este artículo hemos podido ver el uso de Eventos con Spring y así como posibles usos y funcionalidades. Los Eventos de Spring es una herramienta muy útil si además lo unimos, como hemos podido ver, con programación asíncrona y transacciones.

Si necesitas más información puedes escribirnos un comentario o un correo electrónico a refactorizando.web@gmail.com o también nos puedes contactar por nuestras redes sociales Facebook o twitter y te ayudaremos encantados!


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *