Paso de eventos entre beans con SpringFramework Core

De ChuWiki

Con Core de SpringFramework podemos hacer que se instancien varios beans cuya configuración se lee de un fichero. Sin embargo, también podemos usarlo para que se transmitan eventos entre ellos, sin necesidad de verse.

Vamos a hacer aquí un pequeño ejemplo tonto. Dos beans. Uno lanza un evento Saludito y el otro lo recibe y lo saca por pantalla.

El evento que queramos que se envíe debe ser una clase que herede de ApplicationEvent. Así que nos hacemos la clase Saludito que es el evento que queremos transmitir de un bean a otro.

package com.chuidiang.pruebas.spring;

import org.springframework.context.ApplicationEvent;

public class Saludito extends ApplicationEvent {
    String saludo;

    public Saludito(Object source, String saludo) {
        super(source);
        this.saludo = saludo;
    }

    public String getSaludo() {
        return saludo;
    }

    public void setSaludo(String saludo) {
        this.saludo = saludo;
    }
}

Este evento simplemente tiene dentro un String saludo que es la información que queremos que se transmita de un lado a otro.

En bean que genere este evento debe implementar la interface ApplicationContextAware. Esta interface únicamente obliga a tener un método setApplicationContext(ApplicationContext ac) y guardarnos ese ApplicationContext que nos pasan. Lo usaremos para hacer público el evento a todo el que tenga interés. El bean UnAmableQueSaluda puede ser este

package com.chuidiang.pruebas.spring;

import java.util.List;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;

public class UnAmableQueSaluda implements ApplicationContextAware {
    ApplicationContext cx;

    public UnAmableQueSaluda() {
        Thread hilo = new Thread() {
            public void run() {
                while (true)
                    try {
                        Thread.sleep(5000);
                        saluda("¡¡Hola!!");
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        };
        hilo.start();
    }

    @Override
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        cx = arg0;
    }

    public void saluda(String saludo) {
        cx.publishEvent(new Saludito(this, saludo));
    }
}

Simplemente es un bean que en el contructor lanza un hilo con un bucle infinito. En ese bucle, cada cinco segundos saluda(). En saluda() genera un evento Saludito y lo hace público usando el ApplicationContext recibido.

Los bean que tengan interés en cualquier evento deben implementar la interface ApplicationListener. Esta interface nos obliga a poner un método onApplicationEvent(ApplicationEvent e) que es por donde recibiremos el evento. El código del bean ObservadorEvento puede ser este

package com.chuidiang.pruebas.spring;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class ObservadorEvento implements ApplicationListener{

    @Override
    public void onApplicationEvent(ApplicationEvent evento) {
        if (evento instanceof Saludito)
            System.out.println("Me llega "+((Saludito)evento).getSaludo());
    }
}

Cuando llega un evento, comprueba que es de tipo Saludito y lo saca por pantalla.

El fichero bean.xml para configurar SpringFramework con los beans que tiene que instanciar es bastante tonto, puesto que estos beans no requieren configuración. Puede ser como este

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

  <bean id="elQueSaluda" class="com.chuidiang.pruebas.spring.UnAmableQueSaluda">
  </bean>
  
  <bean id="elObservador" class="com.chuidiang.pruebas.spring.ObservadorEvento">
  </bean>
</beans>

En cuanto el código del main, es más tonto todavía

package com.chuidiang.pruebas.spring;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class PruebaBeanContainer {

    public static void main(String[] args) {
        BeanFactory factory = new FileSystemXmlApplicationContext("beans.xml");
    }
}

Lo único que tenemos que tener en cuenta es que la factoria de beans que instanciemos debe heredar de ApplicationContext, puesto que si no, no tendremos disponible todo el tema de eventos. Usamos FileSystemXmlApplicationContext que es la que lee un fichero XML.

Una vez arrancada la aplicación, veremos en pantalla cada cinco segundos el Saludito de marras.

Anotaciones[editar]

Todo esto puede hacerse también con anotaciones y sin herencias de interfaces u otras clases propias de Spring. Podemos verlo en Spring events con anotaciones