web-dev-qa-db-fra.com

Utiliser les annotations @EventListener sur plusieurs événements de Spring

Cela semble être une question assez simple, mais je n'arrive pas à trouver la réponse nulle part.

Au printemps, je peux créer un écouteur pour un événement en utilisant l'annotation @EventListener, comme ceci:

@Component
public class MyListener {

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

Cependant, si j'ai besoin de la même méthode pour écouter plusieurs événements et agir différemment en fonction de l'événement qui se produit?

Intuitivement, je pense à quelque chose de similaire à ceci:

    @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";
        }
    }

Quelle est la bonne manière pour l'annotation EventListener d'écouter plusieurs événements et comment la même méthode peut-elle se différencier en fonction de l'événement réel qui se produit?

Merci beaucoup.

3
pike

Il est théoriquement facile de créer un écouteur d'événements qui écoute plusieurs événements:

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

Mais évidemment, cette approche ne vous donne pas accès à l'événement sous-jacent. Basé sur le javadoc pour EventListener, il ne semble pas possible de faire ce que vous suggérez

Si une méthode annotée prend en charge un seul type d'événement, elle peut déclarer un seul paramètre reflétant le type d'événement à écouter. Si une méthode annotée prend en charge plusieurs types d'événements, cette annotation peut faire référence à un ou plusieurs types d'événements pris en charge à l'aide de l'attribut classes. Voir le javadoc de classes () pour plus de détails.

...

Si (la variable classes) est spécifiée avec une valeur unique, la méthode annotée peut éventuellement accepter un paramètre unique. Toutefois, si cet attribut est spécifié avec plusieurs valeurs, la méthode annotée ne doit déclarer aucun paramètre.

Ainsi, il ne semble pas exister de mécanisme permettant de consommer plusieurs événements et de prendre une action différente en fonction du corps de ces événements. Je suggérerais que cela ne devrait pas être nécessaire, cependant, vous pouvez toujours enregistrer des méthodes @EventListener spécifiques à un événement, puis leur demander simplement d'appeler une méthode partagée pour exécuter toute fonctionnalité commune.

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

6
Ben

Depuis Spring 4.2, vous pouvez utiliser la sous-classe dans la déclaration de méthode pour gérer tous les événements qui étend cette sous-classe:

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

Vous pouvez également restreindre la liste des événements en utilisant l'attribut de l'annotion:

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

Pourquoi ne fais-tu pas quelque chose comme ça?.

À partir de SpringFramework 4.2, vous pouvez publier des événements sans étendre ApplicationEvent.

Lorsque vous avez répondu, vous souhaitez surtout écouter des événements personnalisés. Vous pouvez faire quelque chose comme ça.

Créez une classe de base appelée BaseEvent.

public class BaseEvent {

  private String type;

  public BaseEvent() {}

  public String getType() {
    return type;
  }

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

Considérez cela comme la classe de base chaque fois que vous souhaitez publier une Event personnalisée.

Créons maintenant deux événements personnalisés appelés Example1Event et Example2Event.

Example1Event classe

public class Example1Event extends BaseEvent {

  private String message;

  public Example1Event() {}

  public String getMessage() {
    return message;
  }

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

Example2Event classe

public class Example2Event extends BaseEvent {

  private String message;

  public Example2Event() {}

  public String getMessage() {
    return message;
  }

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

Votre EventListener ressemblerait à ceci.

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

Cela fonctionnera pour ce que vous voulez faire.

1
Indraneel Bende