2012-01-12 9 views
22

Ho 2 diversi tipi di eventi che voglio che la mia classe sia in grado di ascoltare ed elaborare di conseguenza (e in modo diverso).E 'possibile fare in modo che Spring ApplicationListener ascolti per 2 o più tipi di eventi?

ho provato: public class ListenerClass implements ApplicationListener<Foo>, ApplicationListener<Bar>

Questo mi dà un errore che non è possibile implementare la stessa interfaccia per due volte con argomenti diversi.

Non è possibile implementare un listener per ApplicationEvent (o un'altra interfaccia comune implementata da Foo e Bar) e utilizzando instanceof per determinare quale percorso seguire, ho altre opzioni?

Grazie!

risposta

28

Vedere l'aggiornamento Spring 4.2 alla fine di questa risposta!

Primavera < 4,2

Non

davvero.

È possibile utilizzare una classe di super-comune per l'argomento (per esempio ApplicationEvent) o di un'interfaccia comune che Foo e Bar implementa quindi è necessario fitler dal vostro auto.

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

L'altro approccio sarebbe utilizzando due ascoltatori di applicazione

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: tutti e 3 i casi devono essere fagioli di primavera!


Naturalmente è possibile implementare tali funzionalità da soli. Hai almeno due scelte diverse, fallo basare sul framework del dispatcher dell'evento di primavera o farlo completamente separato. Per la seconda scelta sfidare un CDI-Event Mechanim, e cercare alcune porte a molla.

Ho implementato la prima scelta da parte mia alcuni anni (credo nel 2007/2008) fa. Ho a capo un dispatcher di eventi che ha ascoltato tutti gli eventi. È stato configurato tramite un file XML. Questo file xml contiene "riferimenti"! ai metodi di fagioli per ogni evento che dovrebbe stati spediti - questo metodi sarebbero state invocate dalla riflessione. Quindi era possibile avere metodi di handler di eventi fortemente tipizzati (che era l'obiettivo di tale approccio) ma anche avere diversi metodi di handler in una classe. Oggi vorrei saltare il file xml e userei annotazioni e un fagiolo-Post-Processor


Primavera 4.2 aggiornamento di configurazione

Spring 4.2 will have an improved event listener (basi sulle annotazioni) che permette di avere due evento diverso metodi di ascolto in un bean.

@Component 
public class ListenerClass { 

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

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

} 
+0

Sto facendo qualcosa di simile al tuo primo suggerimento in questo momento, ma è un tipo comune tra Foo e Bar (piuttosto che oggetto). La seconda opzione non è un cattivo compromesso, immagino. Non è ancora l'ideale. Speravo davvero che stavo trascurando qualcosa. Sembra che questo debba essere un problema comune. – Luke

+0

Inoltre, 'publishEvent' prende un' ApplicationEvent' in modo che non si possa avere un evento oggetto che viene inviato, dovrebbe essere qualcosa che implementa 'ApplicationEvent' almeno. Potrebbe voler cambiare quello per rendere più chiaro il tuo primo esempio. – Luke

+0

'ApplicationEvent' vs' Object' hai ragione, comunque è lo stesso princip. - L'ho corretto – Ralph

3

Primavera < 4,2

Un po 'più elegante di instanceof o static class è il modello visitatore.Penso che il modello di visitatore fornisca un'alternativa molto utile a quella mancanza della primavera più antica.

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); 
    } 
} 
Problemi correlati