是否可以使Spring ApplicationListener侦听2种或更多类型的事件?

2022-09-01 08:48:03

我有2种不同类型的事件,我希望我的班级能够相应地(以及不同的方式)侦听和处理。

我试过了:public class ListenerClass implements ApplicationListener<Foo>, ApplicationListener<Bar>

这给了我一个错误,你不能用不同的参数实现同一个接口两次。

除了为 ApplicationEvent(或 Foo 和 Bar 将实现的其他一些常见接口)实现侦听器并用于确定要采用的路径之外,我还有其他选择吗?instanceof

谢谢!


答案 1

请参阅本答案末尾的春季4.2更新!

春季< 4.2

没有。

你可以为参数使用一个通用的超类(例如 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-Event Mechanim,并可能搜索一些弹簧端口。

几年前(我猜是在2007/2008年),我自己实施了第一个选择。我领导一个事件调度员,监听所有事件。它是通过 XML 文件配置的。此 xml 文件包含“引用”!对于应该调度的每个事件,bean 中的方法 - 此方法将通过反射调用。因此,可以有强类型的事件处理程序方法(这是该方法的目的),但也可以在一个类中具有多个处理程序方法。现在我会跳过xml文件,而是使用注释和Bean后处理器。


春季 4.2 更新

Spring 4.2 将具有改进的事件侦听器配置(基于注释),使得在一个 Bean 中具有两个不同的事件侦听器方法成为可能。

@Component
public class ListenerClass {

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

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

}

答案 2

春季< 4.2

比游客模式更优雅一点。我认为访客模式为旧Spring的缺点提供了一个非常有用的替代方案。instanceofstatic class

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