监听器模式介绍
编码实现监听器模式
实现一个天气预报的监听器,当天气为下雨或下雪时,通知监听者。
定义一个表示天气事件的抽象类 WeatherEvent,有下雨事件 RainEvent 和下雪事件 SnowEvent。
public abstract class WeatherEvent {
public abstract String getWeather();
}
public class RainEvent extends WeatherEvent {
@Override
public String getWeather() {
return "rain";
}
}
public class SnowEvent extends WeatherEvent {
@Override
public String getWeather() {
return "snow";
}
}
定义事件监听器,分别监听下雪事件和下雨事件。
public interface WeatherListener {
void onWeatherEvent(WeatherEvent event);
}
public class RainListener implements WeatherListener{
@Override
public void onWeatherEvent(WeatherEvent event) {
if (event instanceof RainEvent){
System.out.println("hello " + event.getWeather());
}
}
}
public class SnowListener implements WeatherListener{
@Override
public void onWeatherEvent(WeatherEvent event) {
if (event instanceof SnowEvent){
System.out.println("hello " + event.getWeather());
}
}
}
定义事件广播器,用于广播事件和管理事件监听器。
public interface EventMulticaster {
void multicastEvent(WeatherEvent event);
void addListener(WeatherListener weatherListener);
void removeListener(WeatherListener weatherListener);
}
public abstract class AbstractEventMulter implements EventMulticaster {
private List<WeatherListener> listenerList;
@Override
public void multicastEvent(WeatherEvent event) {
doStart();
listenerList.forEach(i -> i.onWeatherEvent(event));
doEnd();
}
abstract void doStart();
abstract void doEnd();
@Override
public void addListener(WeatherListener weatherListener) {
if (listenerList == null) {
listenerList = new ArrayList<>();
}
listenerList.add(weatherListener);
}
@Override
public void removeListener(WeatherListener weatherListener) {
listenerList.remove(weatherListener);
}
}
public class WeatherEventMulticaster extends AbstractEventMulter {
@Override
void doStart() {
System.out.println("begin broadcast weather event");
}
@Override
void doEnd() {
System.out.println("end broadcast weather event");
}
}
编写测试程序(触发机制)测试天气事件及监听器。
public void testEventMulticast() {
var eventMulticaster = new WeatherEventMulticaster();
var weatherListener = new RainListener();
eventMulticaster.addListener(weatherListener);
eventMulticaster.addListener(new SnowListener());
eventMulticaster.multicastEvent(new SnowEvent());
eventMulticaster.multicastEvent(new RainEvent());
eventMulticaster.removeListener(weatherListener);
eventMulticaster.multicastEvent(new SnowEvent());
eventMulticaster.multicastEvent(new RainEvent());
}
监听器模式的基本要素
- 监听器
- 广播器
- 事件
- 触发机制
SpringBoot 监听器实现
Spring 系统事件监听器由接口 ApplicationListener 定义。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
// 监听到事件后的回调方法
void onApplicationEvent(E event);
}
Spring 系统事件广播器由接口 ApplicationEventMulticaster 定义。
// 事件广播器用于管理 ApplicationListener 和向它们广播事件
public interface ApplicationEventMulticaster {
// 管理 ApplicationListener 的方法:新增、删除
void addApplicationListener(ApplicationListener<?> listener);
void removeApplicationListener(ApplicationListener<?> listener);
void removeAllListeners();
// 向监听器广播事件
void multicastEvent(ApplicationEvent event);
}
Spring 系统事件由抽象类 ApplicationEvent 定义,主要系统事件有。
public abstract class ApplicationEvent extends EventObject {
// 事件发生的时间
private final long timestamp;
// 触发事件的对象(EventObject)
protected transient Object source;
}
SpringBoot 系统事件发送顺序
SpringBoot 启动时系统事件和事件触发顺序由 SpringApplicationRunListener 接口定义。
// 实现类:EventPublishingRunListener
public interface SpringApplicationRunListener {
// ApplicationStartingEvent:SpringApplication run 方法执行时触发
void starting();
// ApplicationEnvironmentPreparedEvent:环境准备好 ApplicationContext 还未创建时
void environmentPrepared(ConfigurableEnvironment environment);
// ApplicationContextInitializedEvent:
void contextPrepared(ConfigurableApplicationContext context);
// ApplicationPreparedEvent:ApplicationContext 已加载未刷新
void contextLoaded(ConfigurableApplicationContext context);
// ApplicationStartedEvent
void started(ConfigurableApplicationContext context);
// ApplicationReadyEvent
void running(ConfigurableApplicationContext context);
// ApplicationFailedEvent:应用发送错误时
void failed(ConfigurableApplicationContext context, Throwable exception);
}
监听器注册
系统监听器和系统初始化器的注册流程基本一致,即在 SpringApplication 的构造方法中通过 SpringFactoriesLoader 加载 ApplicationListener 的实现类,具体流程参照初始化器解析-springboot源码学习/#springfactoriesloader-介绍。
监听器事件触发机制
系统事件触发机制
以 ApplicationStartingEvent 事件为例,最初是在 SpringApplication 的 run 方法中调用 starting 方法触发。
public ConfigurableApplicationContext run(String... args) {
// ...
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
// ...
return context;
}
SpringApplicationRunListeners 类是 SpringApplicationRunListener 的集合,对每一个 RunListener 调用 starting 方法。
class SpringApplicationRunListeners {
private final List<SpringApplicationRunListener> listeners;
// ...
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
}
SpringApplicationRunListener 最终通过 SimpleApplicationEventMulticaster 事件广播器将 ApplicationStartingEvent 事件广播给事件监听器。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
// 将所有监听器注册到广播器中
this.initialMulticaster.addApplicationListener(listener);
}
}
// ...
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
}
改造监听器模式
参照 SpringApplicationRunListener 改造上述天气预报的监听器,引入 WeatherRunListener ,定义 snow 和 rain 方法。通过 Spring 管理广播器和监听器实现自动注入。
@Component
public class WeatherRunListener {
@Resource
private WeatherEventMulticaster eventMulticaster;
public void snow(){
eventMulticaster.multicastEvent(new SnowEvent());
}
public void rain(){
eventMulticaster.multicastEvent(new RainEvent());
}
}
@Component
public class WeatherEventMulticaster extends AbstractEventMulter {
// ...
}
@Component
public class RainListener implements WeatherListener{
// ...
}
// 测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class WeatherRunListenerTest {
@Resource
private WeatherRunListener weatherRunListener;
@Test
public void testSnow() {
weatherRunListener.snow();
}
@Test
public void testRain() {
weatherRunListener.rain();
}
}
multicastEvent 方法解析
上面已经分析到 ApplicationStartingEvent 事件最终是通过 SimpleApplicationEventMulticaster 的 multicastEvent 方法广播给监听器,multicastEvent 方法的主要逻辑是获取监听器,触发监听器的 onApplicationEvent 事件。
@Override
public void multicastEvent(ApplicationEvent event) {
// 获取事件的 class 包装,调用重载方法
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 未指定线程池,返回 null
Executor executor = getTaskExecutor();
// getApplicationListeners 获取对当前事件感兴趣的监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 调用事件监听器的 onApplicationEvent 方法:listener.onApplicationEvent(event);
invokeListener(listener, event);
}
}
}
通过 getApplicationListeners 方法获取对当前事件感兴趣的监听器。首先使用事件源 source 和事件类型 sourceType 构造缓存 cacheKey,避免重复查找,如果 retrieverCache 缓存中不存在,则调用 retrieveApplicationListeners 方法获取对当前事件感兴趣的监听器。
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Quick check for existing entry on ConcurrentHashMap...
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
// ...
return retrieveApplicationListeners(eventType, sourceType, null)
}
重载的 retrieveApplicationListeners 方法才是真正获取监听器的方法。遍历所有 SpringApplication 初始化时加载的监听器(EventPublishingRunListener 构造方法中添加到 SimpleApplicationEventMulticaster 中),依次调用 supportsEvent 方法,将返回为 true 的监听器添加到目标集合中,最后对目标监听器排序返回。
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
// this.defaultRetriever.applicationListeners:EventPublishingRunListener 构造方法中调用 initialMulticaster.addApplicationListener(listener) 方法注册
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
// ...
}
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
return allListeners;
}
supportsEvent 确定给定监听器是否支持给定事件,首先将 listener 包装为 GenericApplicationListener 的实现类,然后调用 supportsEventType 方法和 supportsSourceType 方法确定给定监听器是否支持当前事件。
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
GenericApplicationListener 和 SmartApplicationListener 都是 ApplicationListener 的子接口,增加了 supportsEventType 方法判断监听器是否支持给定的事件类型和 supportsSourceType 方法判断监听器是否支持给定的事件源类型。
如果监听器不是实现自 SmartApplicationListener 或 GenericApplicationListener 则使用 GenericApplicationListenerAdapter 适配器包装,通过 resolveDeclaredEventType 方法解析出监听器支持的事件类型。
自定义监听器
监听器定义方式
方式一、实现 ApplicationListener 接口,通过泛型参数指定监听的事件。
@Order(1)
public class FirstListener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("hello first");
}
}
方式二、实现 SmartApplicationListener 接口,通过 supportsEventType 方法指定监听的事件。
@Order(4)
public class FourthListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationStartedEvent.class.isAssignableFrom(eventType)
|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("hello fourth");
}
}
监听器注册方式
方式一、通过 META-INF/spring.factories 文件注册监听器。
org.springframework.context.ApplicationListener=store.xianglin.sb2.listener.FirstListener,store.xianglin.sb2.listener.FourthListener
方式二、通过调用 SpringApplication.addListeners()
方法注册 SecondListener。
@SpringBootApplication
@MapperScan("store.xianglin.sb2.mapper")
public class SpringBoot2Application {
public static void main(String[] args) {
// SpringApplication.run(SpringBoot2Application.class, args);
var springApplication = new SpringApplication(SpringBoot2Application.class);
springApplication.addInitializers(new SecondInitializer());
springApplication.addListeners(new SecondListener());
springApplication.run(args);
}
}
方式三、通过配置文件注册 ThirdListener,委托给 DelegatingApplicationListener 监听器处理。
context.listener.classes=store.xianglin.sb2.listener.ThirdListener