Is it possible to make a Spring ApplicationListener listen for 2 or more types of events?

后端 未结 2 1489
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-17 07:30

I\'ve got 2 different types of events that I want my class to be able to listen for and process accordingly (and differently).

I tried: public class Listener

相关标签:
2条回答
  • 2021-01-17 08:00

    See Spring 4.2 update at the end of this answer!

    Spring < 4.2

    Not really.

    You can use a common super class for the argument (for example ApplicationEvent) or a common interface that Foo and Bar implements then you must fitler it by your self.

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

    The other approach would be using two Application Listeners

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

    Important: all 3 instances must be spring beans!


    Of course you can implement such functionality by your own. You have at least two different choices, make it based on the spring event dispatcher framework or do it completely separated. For the second choice defently have a look a the CDI-Event Mechanim, and may search for some spring ports.

    I have implemented the first choice by my self some years (I guess in 2007/2008) ago. I have head a event dispatcher that listend to all events. It was configured though an XML file. This xml files contains "references"! to methods in beans for every event that should been dispatched - this methods would been invoked by reflection. So it was possible to have strong typed event handler methods (that was the aim of that approach) but also to have several handler methods in one class. Nowadays I would skip the xml file and would use Annotations and a Bean-Post-Processor


    Spring 4.2 update

    Spring 4.2 will have an improved event listener configuration (bases on annotations) that makes it possible to have two different event listener Methods in one bean.

    @Component
    public class ListenerClass {
    
      @EventListener
      public void handleFooEvent(Foo fooEvent) {...}
    
      @EventListener
      public void handleBarEvent(Bar barEvent) {...}
    
    }
    
    0 讨论(0)
  • 2021-01-17 08:09

    Spring < 4.2

    A little more elegant than instanceof or static class is the visitor pattern. I think the visitor pattern provides a very useful alternative to that shortcoming of older 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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题