目的:
- 理解SpringBoot事件监听机制如何实现?
- 如何实现自己需要的事件、监听器匹配规则?
1.SpringBoot事件监听器原理(源码角度)
在SpringBoot内部事件中已经讲解了SpringBoot内部事件、事件发布、事件监听的流程以及相关的核心接口和类。这里讲解事件监听是如何实现的?
- 流程总述:创建事件 --> 广播器发布事件 --> 根据事件类型从context的listeners集合中匹配到对应的监听器 --> 回调监听器的onApplication()方法。
- 如何根据事件匹配监听器? 不同的监听器中预置可能对应的事件类型,然后通过class.isAssignableFrom()判断传入的事件在监听器内预置事件中是否存在(妙!)。
1.1 SpringBoot启动流程事件监听举例
在SpringBoot启动run()过程中,首先启动的事件是ApplicationStartingEvent。对应run()方法中的listeners.starting(),而实际执行则在EventPublishingRunListener对象中,存在starting()方法。
starting()方法中,首先创建了ApplicationStartingEvent事件,然后通过广播器.multicastEvent()发布了该事件。
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
1.2 事件发布监听关键点
(1)根据传入的事件从所有的listener中匹配对应的监听器。
(2)回调监听器的onApplication()方法。
(1)根据事件匹配监听器
下面代码块中的getApplicationListeners方法是关键,而getApplicationListeners最终执行到retrieveApplicationListeners方法,最后根据supportsEvent()方法中的class.isAssignableFrom() java本地方法方法判断监听器是否匹配传入的事件。
class.isAssignableFrom()方法:
class1.isAssignableFrom(class2) 判定此
class1
对象所表示的类或接口与指定的class2
参数所表示的类或接口是否相同,或是否是其超类或超接口。
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//getApplicationListeners是关键
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
//回调监听器的方法
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
//...
//真正根据事件类型判断监听器的方法
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
//...
}
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
//...
//此处的判断条件是关键部分,supportEvent方法
if (supportsEvent(listener, eventType, sourceType)) {
//...
}
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));
}
@Override
public boolean supportsEventType(ResolvableType resolvableType) {
return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return isAssignableFrom(sourceType, SOURCE_TYPES);
}
//日志LoggingApplicationListener事件当中,预置了EVENT_TYPES事件类型
EVENT_TYPES = { ApplicationStartingEvent.class,
ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class,
ContextClosedEvent.class, ApplicationFailedEvent.class };
//根据传入的事件,匹配是否在事件集合中
isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
(2)回调监听器的方法
@SuppressWarnings({"unchecked", "rawtypes"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//关键点在这里。回调了监听器listener.onApplicationEvent()方法。至此,事件从发布到执行结束
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
2.如何实现自定义事件监听器匹配规则?
自定义监听器匹配规则,暂时还未深入理解。下面这篇文章推荐阅读:https://juejin.cn/post/6955783021224001567