web-dev-qa-db-ja.com

Springの複数のイベントで@EventListenerアノテーションを使用する

これはかなり単純明快な質問のようですが、どこにも答えが見つからないようです。

Springでは、次のように@EventListenerアノテーションを使用してイベントのリスナーを作成できます。

@Component
public class MyListener {

    @EventListener
    public void handleEvent(ContextRefreshedEvent event) {
        ...
    }
}

ただし、複数のイベントをリッスンし、発生するイベントに基づいて異なる動作をするために同じメソッドが必要な場合はどうなりますか?

直感的に、私はこれに似たものを考えています:

    @Component
    public class MyListener {

        @EventListener
        public void handleEvents(ContextRefreshedEvent event, ContextStopped event) {
             String event;
             if(event instanceof ContextRefreshedEvent)
                  event = "Refreshed";
             if(event instanceof ContextStoppedEvent)
                  event = "Stopped";
        }
    }

EventListenerアノテーションが複数のイベントをリッスンする正しい方法は何ですか?同じメソッドが実際に発生するイベントに基づいてどのように区別できるのですか?

どうもありがとう。

7
pike

複数のイベントをリッスンするイベントリスナーを作成することは、名目上簡単です。

@EventListener({EventA.class, EventB.class})
public doSomething() {
   ...
}

ただし、明らかにこのアプローチでは、基になるイベントにアクセスできません。 EventListenerのjavadocに基づいて、あなたが提案していることを行うことができないようです

アノテーション付きメソッドが単一のイベントタイプをサポートする場合、メソッドは、リッスンするイベントタイプを反映する単一のパラメーターを宣言する場合があります。アノテーション付きメソッドが複数のイベントタイプをサポートしている場合、このアノテーションは、classes属性を使用して、サポートされている1つ以上のイベントタイプを参照する場合があります。詳細は、classes()javadocを参照してください。

...

classes)属性が単一の値で指定されている場合、注釈付きメソッドはオプションで単一のパラメーターを受け入れることができます。ただし、この属性が複数の値で指定されている場合、注釈付きメソッドはパラメーターを宣言してはなりません。

したがって、複数のイベントを消費し、それらのイベントの本体に基づいて異なるアクションを実行するメカニズムはないようです。ただし、これは必要ではないことをお勧めします。イベント固有の@EventListenerメソッドを常に登録し、共有メソッドを呼び出して一般的な機能を実行させることもできます。

ソース: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/event/EventListener.html

13
Ben M

Spring 4.2以降では、メソッド宣言でサブクラスを使用して、このサブクラスを拡張するすべてのイベントを処理できます。

@EventListener
public void handleEvent(ApplicationEvent event) {
  // listen all descendants of the ApplicationEvent
}

また、アノテーションの属性を使用して、イベントのリストを絞り込むこともできます。

@EventListener({ContextRefreshedEvent.class, ApplicationReadyEvent.class})
public void handleEvent(Object event) {
  // listen only ContextRefreshedEvent and ApplicationReadyEvent
}
5

このようなことをしてみませんか。

SpringFramework 4.2から、ApplicationEventを拡張せずにイベントを公開できます。

あなたが答えたとき、あなたは主にカスタムイベントを聞きたいと思っています。このようなことができます。

BaseEventという基本クラスを作成します。

public class BaseEvent {

  private String type;

  public BaseEvent() {}

  public String getType() {
    return type;
  }

  public void setType(String type) {
    this.type = type;
  }
}

カスタムEventを公開するときはいつでも、それを基本クラスと見なしてください。

次に、Example1EventおよびExample2Eventという2つのカスタムイベントを作成します。

Example1Eventクラス

public class Example1Event extends BaseEvent {

  private String message;

  public Example1Event() {}

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }
}

Example2Eventクラス

public class Example2Event extends BaseEvent {

  private String message;

  public Example2Event() {}

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }
}

EventListenerは次のようになります。

public class EventReceiver {

  public EventReceiver() {}

  @EventListener
  public void receiveEvent(BaseEvent event) {
    String eventType = event.getType();
    if (eventType.equals("example1")) {
      Example1Event example1Event = (Example1Event) event;
      System.out.println(example1Event.getMessage());
    } else if (eventType.equals("example2")) {
      Example2Event example2Event = (Example2Event) event;
      System.out.println(example2Event.getMessage());
    }
  }
}

これはあなたがしたいことのために働くでしょう。

2
Indraneel Bende

イベントごとに複数のEventListenerを持つことができます。

0
user1589188