自定义监听器实现

自定义监听器实现

为了便于理解SpringBoot的监听器,现在手写实现一个监听器
监听器必须三大对象:

  1. 事件
  2. 监听器
  3. 广播器

事件

在JDK层面有定义一个EventObject事件类型,在Spring层面有定义一个ApplicationEvent。但为了确保我们的事件与JDK、Spring都没有关系。所以我们单独定义一个事件类型

public interface WeatherEvent {
    /**
     * 获取天气状态
     */
    String getWeather();
}
public class SnowEvent implements WeatherEvent {
    @Override
    public String getWeather() {
        return "下雪了";
    }
}
public class RainEvent implements WeatherEvent {
    @Override
    public String getWeather() {
        return "下雨了";
    }
}

事件监听器

JDK中存在一个标记性接口EventListener表明其是一个监听器,没有任何的方法。在Spring层面存在一个ApplicationListener的函数式接口。可以监听ApplicationEvent及其子类型事件。还存在一个SmartApplicationListener通过其supportsEventType可以同时监听多个事件

我们这里的监听器照样不继承自任何类。但是参考自ApplicationListener的实现。通过泛型来决定其所监听的WeatherEvent类型及其子类型

public interface WeatherListener<T> {
    void onWeatherEvent(T event);
}

SnowListener表示其所监听的事件为SnowEvent。最终具体实现在广播器中

public class SnowListener implements WeatherListener<SnowEvent> {
    @Override
    public void onWeatherEvent(SnowEvent event) {
        event.getWeather();
        System.out.println("今天下雪!请增加衣物,做好御寒保护!");
    }
}
public class RainListener implements WeatherListener<RainEvent> {
    @Override
    public void onWeatherEvent(RainEvent event) {
        event.getWeather();
        System.out.println("今天下雨!出门请带好雨伞");
    }
}

广播器

SpringBoot中的广播器存在一个Map缓存。在任何对监听器的变更都会清除该缓存

public interface EventMulticaster {
    // 广播事件
    void multicastEvent(WeatherEvent event);

    // 添加监听器
    void addListener(WeatherListener weaterListener);

    // 删除监听器
    void removeListener(WeatherListener weaterListener);
}

采用模板方法设计模式。底层定义一个接口,在上层采用一个抽象类实现关键步骤,而后可以根据不同的策略实现其中对应的核心逻辑

public abstract class AbstractEventMulticaster implements EventMulticaster {
    // 存放监听器的集合,所有需要监听的事件都存在这里
    private List<WeatherListener> listenerList = new ArrayList<>();

    @Override
    public void multicastEvent(WeatherEvent event) {
    	// 这里可以理解为postProcessBeforeEvent,在事件处理之前调用
        doStart();
        for (WeatherListener weatherListener : listenerList) {
        	// 这里获取WeatherListener的泛型类型
        	// AopUtils.getTargetClass(event)若存在代理时,获取其真实类型
            if (ResolvableType.forInstance(weatherListener).as(WeatherListener.class).getGeneric().isAssignableFrom(AopUtils.getTargetClass(event))) {
                weatherListener.onWeatherEvent(event);
            }
        }
        // 这里可以理解为postProcessAfterEvent,在事件处理之后调用
        doEnd();
    }

    @Override
    public void addListener(WeatherListener weaterListener) {
        listenerList.add(weaterListener);
    }

    @Override
    public void removeListener(WeatherListener weaterListener) {
        listenerList.remove(weaterListener);
    }

    void doEnd() {
    }

    void doStart() {
    }
}

public class WeatherEventMulticaster extends AbstractEventMulticaster {
    @Override
    void doStart() {
        System.out.println("开始广播天气预报!");
    }

    @Override
    void doEnd() {
        System.out.println("广播结束!Over!\n");
    }
}

测试

// 创建广播器
WeatherEventMulticaster eventMulticaster = new WeatherEventMulticaster();
// 创建监听器
RainListener rainListener = new RainListener();
SnowListener snowListener = new SnowListener();
// 添加监听器
eventMulticaster.addListener(rainListener);
eventMulticaster.addListener(snowListener);
// 触发下雨事件
eventMulticaster.multicastEvent(new RainEvent());
// 触发下雪事件
eventMulticaster.multicastEvent(new SnowEvent());

运行结果:

开始广播天气预报!
今天下雨!出门请带好雨伞
广播结束!Over!

开始广播天气预报!
今天下雪!请增加衣物,做好御寒保护!
广播结束!Over!

附录

后期可以考虑出一个注解版本的,但那样的话感觉就需要与Spring框架整合。运用Spring框架提供的能力获取项目中所有的Bean,来判断这些Bean中所有的方法那些存在指定的注解。
SpringBoot框架处理@EventListener注解的思路为:EventListenerMethodProcessor#afterSingletonsInstantiated,最终会将其适配为一个ApplicationListenerMethodAdapter,其中将处理事件类型为declaredEventTypes属性

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

①笶侕濄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值