Publicación y suscripción de eventos con Guava EventBus en una aplicación Java

Escrito por el .
java planeta-codigo programacion
Comentarios

Guava EventBus es una solución simple para la publicación y suscripción de eventos en una misma aplicación y como tal no posee muchas de las capacidades que si tiene JMS o RabbitMQ, sin embargo, en algunos casos puede ser muy útil, una solución sencilla y sin requerimientos adicionales de infraesrtuctura.

Java

En programación los eventos son una buena forma de comunicación que permite desacoplar el emisor del evento del receptor o receptores. Los eventos permiten reaccionar a situaciones que se producen a la aplicación. El emisor los lanza cuando considera adecuado y los receptores se suscriben a los eventos que quieren recibir y actúan según su funcionalidad.

Hay herramientas especificas para eventos en Java está JMS si la aplicación está basada en la plataforma en Java EE, en caso de necesitar un servidor de mensajes adecuado para múltiples plataformas y lenguajes uno de los más conocidos es RabbitMQ. Estas opciones permiten que el emisor y los receptores estén aplicaciones distintas.

En el caso de que el emisor y receptor estén en la misma aplicación una opción más sencilla por no requerir un servidor de mensajería es usando la librería Guava y su funcionalidad de Event Bus. Una de las ventajas de Guava Event Bus es que el receptor no requiere un registro explícito en el emisor como ocurre en algunas de las soluciones con clases Listener de Java.

Para hacer uso de Guava Event Bus hay que obtener una referencia a la clase EventBus que usando Spring se puede definir como un bean singleton en el contenedor de dependencias y ser inyectado en las clases que lo necesiten. Los eventos se envían a haciendo uso del método post() con el objeto que representa el evento como argumento. Los manejadores de los eventos o listener son simplemente un método anotado con @Suscribe y el tipo del evento como argumento, la clases listener han de registrarse en el EventBus y una misma clase con múltiples métodos anotados puede manejar diferentes eventos.

En el contenedor de Spring se define como un bean la clase EventBus que es inicializada con las clases listener con métodos anotados con @Suscribe registradas con el método register().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package io.github.picodotdev.blogbitix.guava;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.google.common.eventbus.EventBus;

@SpringBootApplication
public class Main {

    @Bean
    public EventBus eventBus() {
        EventBus eventbus = new EventBus();
        eventbus.register(new EventListener());
        return eventbus;
    }

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package io.github.picodotdev.blogbitix.guava;

import com.google.common.eventbus.Subscribe;

public class EventListener {
 
    @Subscribe
    public void onEvent(Event event) {
        System.out.printf("Event: %s%n", event.getMessage());
    }
}

En este ejemplo sencillo se lanza un evento cuando se realiza una petición y como reacción a este evento se imprime un mensaje en la salida. Una aplicación real del EventBus será más complicada pero este ejemplo muestra perfectamente el mecanismo de lanzado y recepción de eventos en una misma aplicación. La clase que se lanza como evento en este caso es un POJO sin ningún requerimiento especial.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package io.github.picodotdev.blogbitix.guava;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import com.google.common.eventbus.EventBus;

@RestController
public class DefaultRestController {

    @Autowired
    private EventBus eventbus;

    @RequestMapping("/")
    public Event hello(@RequestParam(value = "message", defaultValue = "Hello World!") String message) {
        Event event = new Event(message);
        eventbus.post(event);
        return event;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package io.github.picodotdev.blogbitix.guava;

public class Event {

    private String message;

    public Event(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

Al realizar peticiones a la aplicación el controlador emite un evento que es recibido por listener al procesar el evento, en la salida de la aplicación aparecen los mensajes.

1
2
Event: Hello World!
Event: A message

En el proyecto hay que incluir como dependencia la librería Guava en este caso usando Gradle.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
plugins {
    id 'java'
    id 'application'
    id 'org.springframework.boot' version '2.1.6.RELEASE'
}

group = 'io.github.picodotdev.blogbitix'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 11
mainClassName = 'io.github.picodotdev.blogbitix.guava.Main'

repositories {
    mavenCentral()
}

dependencies {
    implementation platform("org.springframework.boot:spring-boot-dependencies:2.1.6.RELEASE")

    implementation('org.springframework.boot:spring-boot-starter-web')
    implementation('org.springframework.boot:spring-boot-starter-jersey')
    implementation('com.google.guava:guava:28.0-jre')
}

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.