2012-01-12 7 views
22

Mam 2 różne typy zdarzeń, które chcę, aby moja klasa była w stanie słuchać i odpowiednio przetwarzać (i inaczej).Czy jest możliwe, aby Spring ApplicationListener nasłuchiwał 2 lub więcej typów zdarzeń?

Próbowałem: public class ListenerClass implements ApplicationListener<Foo>, ApplicationListener<Bar>

To daje mi błąd, że nie można realizować ten sam interfejs dwa razy z różnymi argumentami.

Krótko od wdrożenia detektora dla ApplicationEvent (lub jakiegoś innego wspólnego interfejsu, który zaimplementował Foo i Bar) i użycia instanceof do określenia, którą ścieżkę zastosować, czy mam jakieś inne opcje?

Dzięki!

Odpowiedz

28

Zobacz aktualizację Wiosna 4.2 na końcu tej odpowiedzi!

Wiosna < 4,2

Niezupełnie.

Możesz użyć wspólnej super klasy dla argumentu (na przykład ApplicationEvent) lub wspólnego interfejsu, który implementuje Foo i Bar, a następnie musisz dopasować go do siebie.

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

Inne podejście byłoby za pomocą dwóch słuchaczy aplikacji

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

Ważne: wszystkie 3 przypadki muszą być fasola wiosna!


Oczywiście można wdrożyć taką funkcjonalność samodzielnie. Masz co najmniej dwa różne wybory, uczyń to w oparciu o framework dyspozytora wydarzeń wiosennych lub zrób to całkowicie oddzielnie. Jeśli chodzi o drugi wybór, zerknij na mechanizm zdarzeń CDI i wyszukaj niektóre porty sprężynowe.

Zaimplementowałem pierwszy wybór przez kilka lat (jak sądzę w 2007/2008). Mam szefa dyspozytora zdarzeń, który słucha wszystkich wydarzeń. Został skonfigurowany przez plik XML. Ten plik xml zawiera "referencje"! do metod w fasoli dla każdego zdarzenia, które powinno zostać wysłane - metody te zostałyby przywołane przez odbicie. Tak więc możliwe było posiadanie silnych typowych metod obsługi zdarzeń (było to celem tego podejścia), ale także posiadanie kilku metod obsługi w jednej klasie. Obecnie chciałbym pominąć plik xml i użyłby adnotacje i Bean-postprocesor


Wiosna 4,2 zmiana konfiguracji

Spring 4.2 will have an improved event listener (bazuje na adnotacje), który sprawia, że ​​możliwe są dwa różne zdarzenia detektor Metody w jednym komponencie bean.

@Component 
public class ListenerClass { 

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

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

} 
+0

Robię teraz coś podobnego do twojej pierwszej sugestii, ale jest to typowy typ pomiędzy Foo i Bar (a nie obiekt). Druga opcja nie jest chyba złym kompromisem. Nadal nie jest idealny. Naprawdę miałem nadzieję, że coś przeoczyłem. Wygląda na to, że musi to być typowy problem. – Luke

+0

Ponadto, 'publishEvent' przyjmuje' ApplicationEvent', więc nie można było wysłać zdarzenia Object, musi to być coś co implementuje 'ApplicationEvent' przynajmniej. Może chcieć to zmienić, aby twój pierwszy przykład był bardziej przejrzysty. – Luke

+0

'ApplicationEvent' vs' Object', masz rację, w każdym razie jest to ten sam princip. - Poprawiłem to – Ralph

3

Wiosna < 4,2

Nieco bardziej elegancki niż instanceof lub static class jest odwiedzający.Myślę, że wzór gościa stanowi bardzo przydatną alternatywę dla tej wady starszej wiosny.

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); 
    } 
} 
Powiązane problemy