Use @EventListener annotation on multiple events in Spring

pike picture pike · Aug 25, 2017 · Viewed 19.9k times · Source

This seems like a pretty straight forward question, but I can't seem to find the answer anywhere.

In Spring, I can create a listener for an event using the @EventListener annotation, like this:

@Component
public class MyListener {

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

However, what if I need the same method to listen to multiple events and act differently based the event that happens?

Intuitively, I'm thinking something similar to this:

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

What is the correct way for the EventListener annotation to listen to multiple events and how can the same method differentiate based on the actual event that happens?

Answer

Ben M picture Ben M · Aug 25, 2017

It's nominally easy to create an event listener that listens for multiple events:

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

But obviously this approach does not give you access to the underlying event. Based on the javadoc for EventListener it does not appear to be possible to do what you are suggesting

If an annotated method supports a single event type, the method may declare a single parameter that reflects the event type to listen to. If an annotated method supports multiple event types, this annotation may refer to one or more supported event types using the classes attribute. See the classes() javadoc for further details.

...

If (the classes) attribute is specified with a single value, the annotated method may optionally accept a single parameter. However, if this attribute is specified with multiple values, the annotated method must not declare any parameters.

Thus there does not appear to be any mechanism to consume multiple events and take a different action based on the body of those events. I would suggest that this shouldn't be necessary though, you could always register event-specific @EventListener methods, and then just have them call a shared method to perform any common functionality.

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