自定义监听器实现
为了便于理解SpringBoot的监听器,现在手写实现一个监听器
监听器必须三大对象:
- 事件
- 监听器
- 广播器
事件
在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属性