2012-01-12 10 views
22

Tengo 2 tipos diferentes de eventos que deseo que mi clase pueda escuchar y procesar en consecuencia (y de manera diferente).¿Es posible hacer que un Spring ApplicationListener escuche dos o más tipos de eventos?

me trataron: public class ListenerClass implements ApplicationListener<Foo>, ApplicationListener<Bar>

Esto me da un error que no se puede aplicar la misma interfaz dos veces con diferentes argumentos.

A falta de implementar un oyente para ApplicationEvent (o alguna otra interfaz común que implementarían Foo and Bar) y usando instanceof para determinar qué camino tomar, ¿tengo alguna otra opción?

Gracias!

Respuesta

28

¡Consulte la actualización de Spring 4.2 al final de esta respuesta!

primavera < 4,2

No

realmente.

Puede usar una superclase común para el argumento (por ejemplo, ApplicationEvent) o una interfaz común que implementan Foo and Bar, entonces usted debe ajustarla por su cuenta.

public class ListenerClass implements ApplicationListener<ApplicationEvent> { 
    ... 
    if(event instanceOf Foo || event instance of Bar) { 
    } 
} 

El otro enfoque sería usar dos oyentes de aplicación

public class ListenerClass { 

    void onFoo(Foo foo){} 
    void onBar(Bar bar){} 

    static class FooListener implements ApplicationListener<Foo> { 
     ListenerClass listerner; 
     .... 
     public void onApplicationEvent(Foo foo) { 
      listener.onFoo(foo); 
     } 
    } 
    static class BarListener implements ApplicationListener<Bar> { 
     ListenerClass listerner; 
     .... 
     public void onApplicationEvent(Bar bar) { 
      listener.onBar(bar); 
     } 
    } 
} 

Importante: los 3 casos deben ser granos de primavera!


Por supuesto, usted puede implementar dicha funcionalidad por su cuenta. Tiene al menos dos opciones diferentes, hacerla basada en el marco del despachador de eventos de primavera o hacerlo completamente separado. Para la segunda opción, eche un vistazo al Mecanismo de Evento CDI, y puede buscar algunos puertos de primavera.

He implementado la primera opción por mi cuenta hace algunos años (supongo que en 2007/2008). Tengo un despachador de eventos que escucha todos los eventos. Fue configurado a través de un archivo XML. ¡Este archivo xml contiene "referencias"! a métodos en frijoles para cada evento que debería enviarse; este método se invocaría por reflexión. Por lo tanto, era posible tener buenos métodos de manejo de eventos escritos (ese era el objetivo de ese enfoque), pero también tener varios métodos de manejo en una clase. Hoy en día me saltaría el archivo xml y usaría anotaciones y un Bean-Postprocesador


Primavera 4.2 actualización de la configuración

Spring 4.2 will have an improved event listener (bases sobre las anotaciones) que hace posible tener dos eventos diferentes Métodos de escucha en un bean.

@Component 
public class ListenerClass { 

    @EventListener 
    public void handleFooEvent(Foo fooEvent) {...} 

    @EventListener 
    public void handleBarEvent(Bar barEvent) {...} 

} 
+0

Estoy haciendo algo similar a su primera sugerencia en este momento, pero es un tipo común entre Foo y Bar (en lugar de objeto). La segunda opción no es un mal compromiso, supongo. Todavía no es ideal. Realmente estaba esperando que estuviera pasando por alto algo. Parece que esto debe ser un problema común. – Luke

+0

Además, 'publishEvent' toma' ApplicationEvent' para que no pueda enviarse un evento Object, tendría que ser algo que implemente 'ApplicationEvent' al menos. Tal vez quieras cambiar eso para que tu primer ejemplo sea más claro. – Luke

+0

'ApplicationEvent' vs' Object' tienes razón, de todos modos es el mismo principio. - Lo corregí – Ralph

3

primavera < 4,2

Un poco más elegante que instanceof o static class es el patrón de visitante.Creo que el patrón de visitante proporciona una alternativa muy útil a esa deficiencia de Spring anterior.

public class ListenerClass implements ApplicationListener<FooBarBase>, FooBarVisitor { 
    @Override 
    public void onApplicationEvent(FooBarBase fooBarBase) { 
     fooBarBase.accept(this); 
    } 

    @Override 
    public void visitFoo(Foo foo) { 
     System.out.println("Handling Foo Event..."); 
    } 

    @Override 
    public void visitBar(Bar bar) { 
     System.out.println("Handling Bar Event..."); 
    } 
} 

public interface FooBarVisitor { 
    void visitFoo(Foo foo); 
    void visitBar(Bar bar); 
} 

public abstract class FooBarBase extends ApplicationEvent { 
    public FooBarBase(Object source) { 
     super(source); 
    } 

    abstract void accept(FooBarVisitor visitor); 
} 

public class Bar extends FooBarBase { 
    public Bar(Object source) { 
     super(source); 
    } 

    @Override 
    void accept(FooBarVisitor visitor) { 
     visitor.visitBar(this); 
    } 
} 

public class Foo extends FooBarBase { 
    public Foo(Object source) { 
     super(source); 
    } 

    @Override 
    void accept(FooBarVisitor visitor) { 
     visitor.visitFoo(this); 
    } 
} 
Cuestiones relacionadas