Можно ли заставить Spring ApplicationListener прослушивать 2 или более типов событий? - PullRequest
25 голосов
/ 12 января 2012

У меня есть 2 разных типа событий, которые я хочу, чтобы мой класс мог слушать и обрабатывать соответственно (и по-разному).

Я пытался: public class ListenerClass implements ApplicationListener<Foo>, ApplicationListener<Bar>

Это дает мне ошибку, что вы не можете реализовать один и тот же интерфейс дважды с разными аргументами.

Если не реализовать прослушиватель для ApplicationEvent(или какой-нибудь другой общий интерфейс, который реализовали бы Foo и Bar) и используя instanceof, чтобы определить, какой путь выбрать, есть ли у меня другие варианты?

Спасибо!

Ответы [ 2 ]

34 голосов
/ 12 января 2012

См. Обновление Spring 4.2 в конце этого ответа!

Пружина <4.2 </strong>

Не совсем.

Вы можете использовать общий суперкласс для аргумента (например, ApplicationEvent) или общий интерфейс, который реализует Foo и Bar, тогда вы должны настроить его самостоятельно.

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

Другим подходом будет использование двух прослушивателей приложений

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

Важно: все 3 экземпляра должны быть бобами!


Конечно, вы можете реализовать такую ​​функцию самостоятельно. У вас есть по крайней мере два разных варианта: выберите его на основе среды диспетчера событий Spring или сделайте его полностью отдельным. Для второго выбора обязательно посмотрите механизм событий CDI и, возможно, найдите некоторые пружинные порты.

Я реализовал первый выбор несколько лет назад (наверное, в 2007/2008). Я возглавляю диспетчер событий, который посещает все события. Он был настроен через XML-файл. Этот XML-файл содержит «ссылки»! для методов в bean-компонентах для каждого события, которое должно быть отправлено - эти методы будут вызываться отражением. Таким образом, было возможно иметь строго типизированные методы-обработчики событий (что и было целью этого подхода), а также иметь несколько методов-обработчиков в одном классе. В настоящее время я бы пропустил XML-файл и использовал бы аннотации и постпроцессор Bean


Spring 4.2 update

Spring 4.2 будет иметь улучшенную конфигурацию прослушивателя событий (основанную на аннотациях), которая позволяет иметь два разных метода прослушивателя событий в одном компоненте.

@Component
public class ListenerClass {

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

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

}
3 голосов
/ 23 февраля 2016

Spring <4.2 </strong>

Немного более элегантно, чем instanceof или static class - шаблон посетителя.Я думаю, что шаблон посетителя предоставляет очень полезную альтернативу этому недостатку старой Spring.

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...